summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-08-01 12:52:39 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-08-01 12:52:39 -0400
commit432fd93f6884036df59007f09dee86adfb7078ad (patch)
tree6b7b702984775a66f73d6831cd2a8749156147ba
parent189346c45a4907479f083c854469a896dcf3b581 (diff)
downloadpasslib-432fd93f6884036df59007f09dee86adfb7078ad.tar.gz
project-wide whitespace & comment cleanup (it's been a couple of years)
-rw-r--r--admin/pypi_upload.sh4
-rw-r--r--docs/conf.py66
-rw-r--r--docs/lib/passlib.apps.rst2
-rw-r--r--docs/lib/passlib.context-tutorial.rst2
-rw-r--r--docs/lib/passlib.hash.bcrypt.rst2
-rw-r--r--docs/lib/passlib.hash.cisco_pix.rst8
-rw-r--r--docs/lib/passlib.hash.grub_pbkdf2_sha512.rst6
-rw-r--r--docs/lib/passlib.hash.hex_digests.rst9
-rw-r--r--docs/lib/passlib.hash.ldap_crypt.rst2
-rw-r--r--docs/lib/passlib.hash.msdcc.rst4
-rw-r--r--docs/lib/passlib.hash.mysql323.rst2
-rw-r--r--docs/lib/passlib.hash.oracle10.rst10
-rw-r--r--docs/lib/passlib.hash.oracle11.rst2
-rw-r--r--docs/lib/passlib.hash.postgres_md5.rst2
-rw-r--r--docs/lib/passlib.hash.sun_md5_crypt.rst6
-rw-r--r--docs/lib/passlib.hosts.rst2
-rw-r--r--docs/lib/passlib.registry.rst8
-rw-r--r--docs/lib/passlib.utils.handlers.rst32
-rw-r--r--docs/modular_crypt_format.rst6
-rw-r--r--docs/new_app_quickstart.rst20
-rw-r--r--passlib/_setup/docdist.py38
-rw-r--r--passlib/_setup/stamp.py18
-rw-r--r--passlib/apache.py105
-rw-r--r--passlib/apps.py85
-rw-r--r--passlib/context.py237
-rw-r--r--passlib/exc.py34
-rw-r--r--passlib/ext/django/models.py24
-rw-r--r--passlib/ext/django/utils.py32
-rw-r--r--passlib/handlers/bcrypt.py73
-rw-r--r--passlib/handlers/cisco.py51
-rw-r--r--passlib/handlers/des_crypt.py117
-rw-r--r--passlib/handlers/digests.py53
-rw-r--r--passlib/handlers/django.py33
-rw-r--r--passlib/handlers/fshp.py77
-rw-r--r--passlib/handlers/ldap_digests.py55
-rw-r--r--passlib/handlers/md5_crypt.py99
-rw-r--r--passlib/handlers/misc.py27
-rw-r--r--passlib/handlers/mssql.py61
-rw-r--r--passlib/handlers/mysql.py57
-rw-r--r--passlib/handlers/oracle.py88
-rw-r--r--passlib/handlers/pbkdf2.py175
-rw-r--r--passlib/handlers/phpass.py53
-rw-r--r--passlib/handlers/postgres.py41
-rw-r--r--passlib/handlers/roundup.py27
-rw-r--r--passlib/handlers/scram.py365
-rw-r--r--passlib/handlers/sha1_crypt.py55
-rw-r--r--passlib/handlers/sha2_crypt.py103
-rw-r--r--passlib/handlers/sun_md5_crypt.py169
-rw-r--r--passlib/handlers/windows.py61
-rw-r--r--passlib/hash.py16
-rw-r--r--passlib/hosts.py78
-rw-r--r--passlib/ifc.py56
-rw-r--r--passlib/registry.py24
-rw-r--r--passlib/tests/__main__.py2
-rw-r--r--passlib/tests/_test_bad_register.py6
-rw-r--r--passlib/tests/backports.py40
-rw-r--r--passlib/tests/test_apache.py74
-rw-r--r--passlib/tests/test_apps.py36
-rw-r--r--passlib/tests/test_context.py124
-rw-r--r--passlib/tests/test_context_deprecated.py210
-rw-r--r--passlib/tests/test_ext_django.py64
-rw-r--r--passlib/tests/test_handlers.py244
-rw-r--r--passlib/tests/test_hosts.py36
-rw-r--r--passlib/tests/test_registry.py66
-rw-r--r--passlib/tests/test_utils.py112
-rw-r--r--passlib/tests/test_utils_crypto.py74
-rw-r--r--passlib/tests/test_utils_handlers.py114
-rw-r--r--passlib/tests/test_win32.py24
-rw-r--r--passlib/tests/utils.py252
-rw-r--r--passlib/utils/__init__.py146
-rw-r--r--passlib/utils/_blowfish/__init__.py46
-rw-r--r--passlib/utils/_blowfish/_gen_files.py18
-rw-r--r--passlib/utils/_blowfish/base.py46
-rw-r--r--passlib/utils/_blowfish/unrolled.py18
-rw-r--r--passlib/utils/compat.py12
-rw-r--r--passlib/utils/des.py103
-rw-r--r--passlib/utils/handlers.py239
-rw-r--r--passlib/utils/md4.py84
-rw-r--r--passlib/utils/pbkdf2.py52
-rw-r--r--passlib/win32.py36
-rw-r--r--setup.py46
-rw-r--r--tox.ini2
82 files changed, 2550 insertions, 2558 deletions
diff --git a/admin/pypi_upload.sh b/admin/pypi_upload.sh
index 12a9430..2ecdcf1 100644
--- a/admin/pypi_upload.sh
+++ b/admin/pypi_upload.sh
@@ -7,8 +7,8 @@
# and make it more failure-proof
#
-#TODO: run through all builds *first*, to make sure they work.
-# re-clean, run pypi upload, gc upload
+# TODO: run through all builds *first*, to make sure they work.
+# re-clean, run pypi upload, gc upload
# clean dir
rm -rf build dist
diff --git a/docs/conf.py b/docs/conf.py
index f1f6f3b..1c8267f 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -15,7 +15,7 @@ import sys, os
options = os.environ.get("PASSLIB_DOCS", "").split(",")
-#make sure passlib in sys.path
+# make sure passlib in sys.path
doc_root = os.path.abspath(os.path.join(__file__,os.path.pardir))
source_root = os.path.abspath(os.path.join(doc_root,os.path.pardir))
sys.path.insert(0, source_root)
@@ -23,14 +23,14 @@ sys.path.insert(0, source_root)
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+##sys.path.insert(0, os.path.abspath('.'))
-#building the docs requires the Cloud sphinx theme & extensions
+# building the docs requires the Cloud sphinx theme & extensions
# https://bitbucket.org/ecollins/cloud_sptheme
-#which contains some sphinx extensions used by passlib
+# which contains some sphinx extensions used by passlib
import cloud_sptheme as csp
-#hack to make autodoc generate documentation from the correct class...
+# hack to make autodoc generate documentation from the correct class...
import passlib.utils.md4 as md4_mod
md4_mod.md4 = md4_mod._builtin_md4
@@ -46,13 +46,13 @@ extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
- #add autdoc support for ReST sections in class/function docstrings
+ # add autdoc support for ReST sections in class/function docstrings
'cloud_sptheme.ext.autodoc_sections',
- #adds extra ids & classes to genindex html, for additional styling
+ # adds extra ids & classes to genindex html, for additional styling
'cloud_sptheme.ext.index_styling',
- #inserts toc into right hand nav bar (ala old style python docs)
+ # inserts toc into right hand nav bar (ala old style python docs)
'cloud_sptheme.ext.relbar_toc',
# replace sphinx :samp: role handler with one that allows escaped {} chars
@@ -91,13 +91,13 @@ version = csp.get_version(release)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+##language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+##today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+##today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -110,18 +110,18 @@ exclude_patterns = [
]
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+##default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+##add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+##show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
@@ -185,37 +185,37 @@ html_last_updated_fmt = '%b %d, %Y'
html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+##html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+##html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+##html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+##html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+##html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+##html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+##html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+##html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+##html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+##html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = project + 'Doc'
@@ -224,10 +224,10 @@ htmlhelp_basename = project + 'Doc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
+##latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
+##latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
@@ -238,26 +238,26 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+##latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+##latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+##latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+##latex_show_urls = False
# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
+##latex_preamble = ''
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+##latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+##latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
diff --git a/docs/lib/passlib.apps.rst b/docs/lib/passlib.apps.rst
index ea47730..dee0125 100644
--- a/docs/lib/passlib.apps.rst
+++ b/docs/lib/passlib.apps.rst
@@ -107,7 +107,7 @@ Passlib provides two contexts related to ldap hashes:
>>> from passlib.apps import ldap_context
>>> ldap_context = ldap_context.replace(default="ldap_salted_md5")
- >>> #the new context object will now default to {SMD5}:
+ >>> # the new context object will now default to {SMD5}:
>>> ldap_context.encrypt("password")
'{SMD5}T9f89F591P3fFh1jz/YtW4aWD5s='
diff --git a/docs/lib/passlib.context-tutorial.rst b/docs/lib/passlib.context-tutorial.rst
index 953bc51..e6d3b1d 100644
--- a/docs/lib/passlib.context-tutorial.rst
+++ b/docs/lib/passlib.context-tutorial.rst
@@ -441,7 +441,7 @@ Applications which choose to use a policy file will typically want
to create the CryptContext at the module level, and then load
the configuration once the application starts:
-1. Within a common module in your application (eg ``myapp.model.security``)::
+1. Within a common module in your application (e.g. ``myapp.model.security``)::
#
# create a crypt context that can be imported and used wherever is needed...
diff --git a/docs/lib/passlib.hash.bcrypt.rst b/docs/lib/passlib.hash.bcrypt.rst
index 1c7fa49..1a2cce7 100644
--- a/docs/lib/passlib.hash.bcrypt.rst
+++ b/docs/lib/passlib.hash.bcrypt.rst
@@ -22,7 +22,7 @@ for new applications. This class can be used directly as follows::
>>> bcrypt.encrypt("password", rounds=8)
'$2a$08$8wmNsdCH.M21f.LSBSnYjQrZ9l1EmtBc9uNPGL.9l75YE8D8FlnZC'
- >>> #verify password
+ >>> # verify password
>>> bcrypt.verify("password", h)
True
>>> bcrypt.verify("wrong", h)
diff --git a/docs/lib/passlib.hash.cisco_pix.rst b/docs/lib/passlib.hash.cisco_pix.rst
index cffd0a1..311409b 100644
--- a/docs/lib/passlib.hash.cisco_pix.rst
+++ b/docs/lib/passlib.hash.cisco_pix.rst
@@ -23,13 +23,13 @@ PIX firewalls. This class can be used directly as follows::
>>> hash
'A5XOy94YKDPXCo7U'
- >>> #verify correct password
+ >>> # verify correct password
>>> pix.verify("password", hash, user="user")
True
- >>> #verify correct password w/ wrong username
+ >>> # verify correct password w/ wrong username
>>> pm.verify("password", hash, user="other")
False
- >>> #verify incorrect password
+ >>> # verify incorrect password
>>> pm.verify("letmein", hash, user="user")
False
@@ -92,7 +92,7 @@ This algorithm is not suitable for *any* use besides manipulating existing
Cisco PIX hashes, due to the following flaws:
* It's use of the username as a salt value (and only the first four characters
- at that), means that common usernames (eg ``admin``, ``cisco``) will occur
+ at that), means that common usernames (e.g. ``admin``, ``cisco``) will occur
more frequently as salts, weakening the effectiveness of the salt in
foiling pre-computed tables.
diff --git a/docs/lib/passlib.hash.grub_pbkdf2_sha512.rst b/docs/lib/passlib.hash.grub_pbkdf2_sha512.rst
index 5f82597..279ac57 100644
--- a/docs/lib/passlib.hash.grub_pbkdf2_sha512.rst
+++ b/docs/lib/passlib.hash.grub_pbkdf2_sha512.rst
@@ -56,16 +56,16 @@ The result is then encoded into hexidecimal.
>>> from passlib.hash import pbkdf2_sha512, grub_pbkdf2_sha512
- >>> #given a pbkdf2_sha512 hash...
+ >>> # given a pbkdf2_sha512 hash...
>>> h = pbkdf2_sha512.encrypt("password")
>>> h
'$pbkdf2-sha512$6400$y6vYff3SihJiqumIrNXwGw$NobVwyUlVI52/Cvrguwli5fX6XgKHNUf7fWWS2VgoWEevaTCiZx4OCYhwGFwzUAuz/g1zQVSIf.9JEb0BEVEEA'
- >>> #it can be parsed into options
+ >>> # it can be parsed into options
>>> hobj = pbkdf2_sha512.from_string(h)
>>> rounds, salt, chk = hobj.rounds, hobj.salt, hobj.checksum
- >>> #and a new grub hash can be created
+ >>> # and a new grub hash can be created
>>> gobj = grub_pbkdf2_sha512(rounds=rounds, salt=salt, checksum=chk)
>>> g = gobj.to_string()
>>> g
diff --git a/docs/lib/passlib.hash.hex_digests.rst b/docs/lib/passlib.hash.hex_digests.rst
index d9d9cb0..0f8f5fd 100644
--- a/docs/lib/passlib.hash.hex_digests.rst
+++ b/docs/lib/passlib.hash.hex_digests.rst
@@ -22,14 +22,17 @@ and can be used directly as follows::
>>> from passlib.hash import hex_sha1 as hex_sha1
- >>> #encrypt password
+ >>> # encrypt password
>>> h = hex_sha1.encrypt("password")
>>> h
'5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8'
- >>> hex_sha1.verify("password", h) #verify correct password
+ >>> # verify correct password
+ >>> hex_sha1.verify("password", h)
True
- >>> hex_sha1.verify("secret", h) #verify incorrect password
+
+ >>> # verify incorrect password
+ >>> hex_sha1.verify("secret", h)
False
.. seealso:: the generic :ref:`PasswordHash usage examples <password-hash-examples>`
diff --git a/docs/lib/passlib.hash.ldap_crypt.rst b/docs/lib/passlib.hash.ldap_crypt.rst
index 2ba7e33..745716f 100644
--- a/docs/lib/passlib.hash.ldap_crypt.rst
+++ b/docs/lib/passlib.hash.ldap_crypt.rst
@@ -56,7 +56,7 @@ Interface
.. class:: ldap_sha512_crypt()
All of these classes have the same interface as their corresponding
- underlying hash (eg :class:`des_crypt`, :class:`md5_crypt`, etc).
+ underlying hash (e.g. :class:`des_crypt`, :class:`md5_crypt`, etc).
.. rubric:: Footnotes
diff --git a/docs/lib/passlib.hash.msdcc.rst b/docs/lib/passlib.hash.msdcc.rst
index 085ebb5..ead1eea 100644
--- a/docs/lib/passlib.hash.msdcc.rst
+++ b/docs/lib/passlib.hash.msdcc.rst
@@ -1,4 +1,4 @@
-.. index::
+.. index::
single: Windows; Domain Cached Credentials
see: mscash; msdcc
see: mscache; msdcc
@@ -83,7 +83,7 @@ This algorithm is should not be used for any purpose besides
manipulating existing DCC v1 hashes, due to the following flaws:
* It's use of the username as a salt value (and lower-case at that),
- means that common usernames (eg ``Administrator``) will occur
+ means that common usernames (e.g. ``Administrator``) will occur
more frequently as salts, weakening the effectiveness of the salt in
foiling pre-computed tables.
diff --git a/docs/lib/passlib.hash.mysql323.rst b/docs/lib/passlib.hash.mysql323.rst
index 8182b8f..80272b4 100644
--- a/docs/lib/passlib.hash.mysql323.rst
+++ b/docs/lib/passlib.hash.mysql323.rst
@@ -27,7 +27,7 @@ That aside, this class can be used as follows::
>>> mysql323.encrypt("password")
'5d2e19393cc5ef67'
- >>> #verify correct password
+ >>> # verify correct password
>>> mysql323.verify("password", '5d2e19393cc5ef67')
True
>>> mysql323.verify("secret", '5d2e19393cc5ef67')
diff --git a/docs/lib/passlib.hash.oracle10.rst b/docs/lib/passlib.hash.oracle10.rst
index 540f086..5d878ba 100644
--- a/docs/lib/passlib.hash.oracle10.rst
+++ b/docs/lib/passlib.hash.oracle10.rst
@@ -16,18 +16,18 @@ a username for all encrypt/verify operations)::
>>> from passlib.hash import oracle10 as oracle10
- >>> #encrypt password using specified username
+ >>> # encrypt password using specified username
>>> hash = oracle10.encrypt("password", user="username")
>>> hash
'872805F3F4C83365'
- >>> #verify correct password
+ >>> # verify correct password
>>> oracle10.verify("password", hash, user="username")
True
- >>> #verify correct password w/ wrong username
+ >>> # verify correct password w/ wrong username
>>> oracle10.verify("password", hash, user="somebody")
False
- >>> #verify incorrect password
+ >>> # verify incorrect password
>>> oracle10.verify("letmein", hash, user="username")
False
@@ -75,7 +75,7 @@ This algorithm it not suitable for *any* use besides manipulating existing
Oracle10 account passwords, due to the following flaws [#flaws]_:
* It's use of the username as a salt value means that common usernames
- (eg ``system``) will occur more frequently as salts,
+ (e.g. ``system``) will occur more frequently as salts,
weakening the effectiveness of the salt in foiling pre-computed tables.
* The fact that it is case insensitive, and simply concatenates the username
diff --git a/docs/lib/passlib.hash.oracle11.rst b/docs/lib/passlib.hash.oracle11.rst
index 8eb8d80..68f21c6 100644
--- a/docs/lib/passlib.hash.oracle11.rst
+++ b/docs/lib/passlib.hash.oracle11.rst
@@ -10,7 +10,7 @@ This class can be can be used directly as follows::
>>> from passlib.hash import oracle11 as oracle11
- >>> #generate new salt, encrypt password
+ >>> # generate new salt, encrypt password
>>> hash = oracle11.encrypt("password")
>>> hash
'S:4143053633E59B4992A8EA17D2FF542C9EDEB335C886EED9C80450C1B4E6'
diff --git a/docs/lib/passlib.hash.postgres_md5.rst b/docs/lib/passlib.hash.postgres_md5.rst
index cddaae1..72144e5 100644
--- a/docs/lib/passlib.hash.postgres_md5.rst
+++ b/docs/lib/passlib.hash.postgres_md5.rst
@@ -53,7 +53,7 @@ This algorithm it not suitable for *any* use besides manipulating existing
PostgreSQL account passwords, due to the following flaws:
* It's use of the username as a salt value means that common usernames
- (eg ``admin``, ``root``, ``postgres``) will occur more frequently as salts,
+ (e.g. ``admin``, ``root``, ``postgres``) will occur more frequently as salts,
weakening the effectiveness of the salt in foiling pre-computed tables.
* Since the keyspace of ``user+password`` is still a subset of ascii characters,
diff --git a/docs/lib/passlib.hash.sun_md5_crypt.rst b/docs/lib/passlib.hash.sun_md5_crypt.rst
index 956cdee..dd9e406 100644
--- a/docs/lib/passlib.hash.sun_md5_crypt.rst
+++ b/docs/lib/passlib.hash.sun_md5_crypt.rst
@@ -134,7 +134,7 @@ The documentation hints that this stems from a bug within the production
implementation's parser. This bug causes the implementation to return
``$$``-format hashes when passed a configuration string that ends with ``$``.
It returns the intended original format & checksum
-only if there is at least one letter after the ``$``, eg :samp:`$md5${salt}$x`.
+only if there is at least one letter after the ``$``, e.g. :samp:`$md5${salt}$x`.
Passlib attempts to accomodate both formats using the special ``bare_salt``
keyword. It is set to ``True`` to indicate a configuration or hash string which
@@ -164,12 +164,12 @@ deviates from the official implementation in the following ways:
* Rounds encoding
- The underlying scheme implicitly allows rounds to have zero padding (eg ``$md5,rounds=001$abc$``),
+ The underlying scheme implicitly allows rounds to have zero padding (e.g. ``$md5,rounds=001$abc$``),
and also allows 0 rounds to be specified two ways (``$md5$abc$`` and ``$md5,rounds=0$abc$``).
Allowing either of these would result in multiple possible checksums
for the same password & salt. To prevent ambiguity,
Passlib will throw a :exc:`ValueError` if the rounds value is zero-padded,
- or specified explicitly as 0 (eg ``$md5,rounds=0$abc$``).
+ or specified explicitly as 0 (e.g. ``$md5,rounds=0$abc$``).
.. _smc-quirks:
diff --git a/docs/lib/passlib.hosts.rst b/docs/lib/passlib.hosts.rst
index 954bf03..cef0335 100644
--- a/docs/lib/passlib.hosts.rst
+++ b/docs/lib/passlib.hosts.rst
@@ -119,7 +119,7 @@ Current Host OS
As an example, this can be used in conjunction with stdlib's :mod:`!spwd` module
to verify user passwords on the local system::
- >>> #NOTE/WARNING: this example requires running as root on most systems.
+ >>> # NOTE/WARNING: this example requires running as root on most systems.
>>> import spwd, os
>>> from passlib.hosts import host_context
>>> hash = spwd.getspnam(os.environ['USER']).sp_pwd
diff --git a/docs/lib/passlib.registry.rst b/docs/lib/passlib.registry.rst
index 6302cb7..2457cb1 100644
--- a/docs/lib/passlib.registry.rst
+++ b/docs/lib/passlib.registry.rst
@@ -41,19 +41,19 @@ Usage
=====
Example showing how to use :func:`!registry_crypt_handler_path`::
- >>> #register the location of a handler without loading it
+ >>> # register the location of a handler without loading it
>>> from passlib.registry import register_crypt_handler_path
>>> register_crypt_handler_path("myhash", "myapp.support.hashes")
- >>> #even before being loaded, it's name will show up as available
+ >>> # even before being loaded, it's name will show up as available
>>> from passlib.registry import list_crypt_handlers
>>> 'myhash' in list_crypt_handlers()
True
>>> 'myhash' in list_crypt_handlers(loaded_only=True)
False
- >>> #when the name "myhash" is next referenced,
- >>> #the class "myhash" will be imported from the module "myapp.support.hashes"
+ >>> # when the name "myhash" is next referenced,
+ >>> # the class "myhash" will be imported from the module "myapp.support.hashes"
>>> from passlib.context import CryptContext
>>> cc = CryptContext(schemes=["myhash"]) #<-- this will cause autoimport
diff --git a/docs/lib/passlib.utils.handlers.rst b/docs/lib/passlib.utils.handlers.rst
index 06028c2..6b4799a 100644
--- a/docs/lib/passlib.utils.handlers.rst
+++ b/docs/lib/passlib.utils.handlers.rst
@@ -170,26 +170,26 @@ of the unittest for :class:`passlib.hash.des_crypt`::
from passlib.hash import des_crypt
from passlib.tests.utils import HandlerCase
- #create a subclass for the handler...
+ # create a subclass for the handler...
class DesCryptTest(HandlerCase):
"test des-crypt algorithm"
- #: [required] - store the handler object itself in the handler attribute
+ # [required] - store the handler object itself in the handler attribute
handler = des_crypt
- #: [optional] - if your hash only uses the first X characters of the password,
- #: set that value here. otherwise leave the default (-1).
+ # [optional] - if your hash only uses the first X characters of the password,
+ # set that value here. otherwise leave the default (-1).
secret_size = 8
- #: [required] - this should be a list of (password, hash) pairs,
- # which should all verify correctly using your handler.
- # it is recommend include pairs which test all of the following:
+ # [required] - this should be a list of (password, hash) pairs,
+ # which should all verify correctly using your handler.
+ # it is recommend include pairs which test all of the following:
#
- # * empty string & short strings for passwords
- # * passwords with 2 byte unicode characters
- # * hashes with varying salts, rounds, and other options
+ # * empty string & short strings for passwords
+ # * passwords with 2 byte unicode characters
+ # * hashes with varying salts, rounds, and other options
known_correct_hashes = (
- #format: (password, hash)
+ # format: (password, hash)
('', 'OgAwTx2l6NADI'),
(' ', '/Hk.VPuwQTXbc'),
('test', 'N1tQbOFcM5fpg'),
@@ -199,13 +199,13 @@ of the unittest for :class:`passlib.hash.des_crypt`::
(u'hell\u00D6', 'saykDgk3BPZ9E'),
)
- #: [optional] - if there are hashes which are similar in format
- #: to your handler, and you want to make sure :meth:`identify`
- #: does not return ``True`` for such hashes,
- #: list them here. otherwise this can be omitted.
+ # [optional] - if there are hashes which are similar in format
+ # to your handler, and you want to make sure :meth:`identify`
+ # does not return ``True`` for such hashes,
+ # list them here. otherwise this can be omitted.
#
known_unidentified_hashes = [
- #bad char in otherwise correctly formatted hash
+ # bad char in otherwise correctly formatted hash
'!gAwTx2l6NADI',
]
diff --git a/docs/modular_crypt_format.rst b/docs/modular_crypt_format.rst
index aa564fb..6457170 100644
--- a/docs/modular_crypt_format.rst
+++ b/docs/modular_crypt_format.rst
@@ -46,7 +46,7 @@ by the modular crypt format hashes found in passlib:
1. Hash strings must use only 7-bit ascii characters.
No known OS or application generates hashes which violate this rule.
- However, some systems (eg Linux's shadow routines) will happily
+ However, some systems (e.g. Linux's shadow routines) will happily
and correctly accept hashes which contain 8-bit characters in their salt.
This is probably a case of "permissive in what you accept,
strict in what you generate".
@@ -58,13 +58,13 @@ by the modular crypt format hashes found in passlib:
Initially, most schemes adhereing to this format
only used a single digit to identify the hash
- (eg ``$1$`` for :class:`!md5_crypt`).
+ (e.g. ``$1$`` for :class:`!md5_crypt`).
Because of this, many systems only look at the first
character when attempting to distinguish hashes.
Despite this, as Unix systems have branched off,
new hashes have been developed which used larger
- identifying strings (eg ``$sha1$`` for :class:`~passlib.hash.sha1_crypt`);
+ identifying strings (e.g. ``$sha1$`` for :class:`~passlib.hash.sha1_crypt`);
so in general identifier strings should not be assumed to use a single character.
3. Hashes should contain only ascii letters ``a``-``z`` and ``A``-``Z``,
diff --git a/docs/new_app_quickstart.rst b/docs/new_app_quickstart.rst
index 4824fac..a036eb5 100644
--- a/docs/new_app_quickstart.rst
+++ b/docs/new_app_quickstart.rst
@@ -16,19 +16,19 @@ and defaults to 40000 hash iterations for increased strength.
For applications which want to quickly add password hashing,
all they need to do is the following::
- >>> #import the context under an app-specific name (so it can easily be replaced later)
+ >>> # import the context under an app-specific name (so it can easily be replaced later)
>>> from passlib.apps import custom_app_context as pwd_context
- >>> #encrypting a password...
+ >>> # encrypting a password...
>>> hash = pwd_context.encrypt("somepass")
- >>> #verifying a password...
+ >>> # verifying a password...
>>> ok = pwd_context.verify("somepass", hash)
- >>> #[optional] encrypting a password for an admin account...
- >>> # the custom_app_context is preconfigured so that
- >>> # if the category is set to "admin" instead of None,
- >>> # it uses a stronger setting of 80000 rounds:
+ >>> # [optional] encrypting a password for an admin account...
+ >>> # the custom_app_context is preconfigured so that
+ >>> # if the category is set to "admin" instead of None,
+ >>> # it uses a stronger setting of 80000 rounds:
>>> hash = pwd_context.encrypt("somepass", category="admin")
For applications which started using this preset, but whose needs
@@ -89,7 +89,7 @@ this matter of concern is what motivated the development of SHA512-Crypt.
As well, its rounds parameter is logarithmically scaled,
making it hard to fine-tune the amount of time taken to verify passwords;
which can be an issue for applications that handle a large number
-of simultaneous logon attempts (eg web apps).
+of simultaneous logon attempts (e.g. web apps).
.. note::
@@ -185,12 +185,12 @@ to manage your hashes, and relating configuration information.
Insert the following code into your application::
#
- #import the CryptContext class, used to handle all hashing...
+ # import the CryptContext class, used to handle all hashing...
#
from passlib.context import CryptContext
#
- #create a single global instance for your app...
+ # create a single global instance for your app...
#
pwd_context = CryptContext(
# replace this list with the hash(es) you wish to support.
diff --git a/passlib/_setup/docdist.py b/passlib/_setup/docdist.py
index 4532e95..dadb4b5 100644
--- a/passlib/_setup/docdist.py
+++ b/passlib/_setup/docdist.py
@@ -1,35 +1,35 @@
"custom command to build doc.zip file"
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import os
from distutils import dir_util
from distutils.cmd import Command
from distutils.errors import *
from distutils.spawn import spawn
-#local
+# local
__all__ = [
"docdist"
]
-#=========================================================
-#command
-#=========================================================
+#=============================================================================
+# command
+#=============================================================================
class docdist(Command):
description = "create zip file containing standalone html docs"
-
+
user_options = [
('build-dir=', None, 'Build directory'),
('dist-dir=', 'd',
"directory to put the source distribution archive(s) in "
- "[default: dist]"),
+ "[default: dist]"),
('format=', 'f',
"archive format to create (tar, ztar, gztar, zip)"),
('sign', 's', 'sign files using gpg'),
('identity=', 'i', 'GPG identity used to sign files'),
]
-
+
def initialize_options(self):
self.build_dir = None
self.dist_dir = None
@@ -37,7 +37,7 @@ class docdist(Command):
self.keep_temp = False
self.sign = False
self.identity = None
-
+
def finalize_options(self):
if self.identity and not self.sign:
raise DistutilsOptionError(
@@ -50,7 +50,7 @@ class docdist(Command):
self.dist_dir = "dist"
if not self.format:
self.format = "zip"
-
+
def run(self):
# call build sphinx to build docs
self.run_command("build_sphinx")
@@ -77,11 +77,11 @@ class docdist(Command):
gpg_args[2:2] = ["--local-user", self.identity]
spawn(gpg_args,
dry_run=self.dry_run)
-
- #cleanup
+
+ # cleanup
if not self.keep_temp:
dir_util.remove_tree(tmp_dir, dry_run=self.dry_run)
-
-#=========================================================
-#eof
-#=========================================================
+
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/_setup/stamp.py b/passlib/_setup/stamp.py
index e3127e4..dfa62bc 100644
--- a/passlib/_setup/stamp.py
+++ b/passlib/_setup/stamp.py
@@ -1,22 +1,22 @@
"update version string during build"
-#=========================================================
+#=============================================================================
# imports
-#=========================================================
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import os
import re
import time
from distutils.dist import Distribution
-#pkg
-#local
+# pkg
+# local
__all__ = [
"stamp_source",
"stamp_distutils_output",
]
-#=========================================================
+#=============================================================================
# helpers
-#=========================================================
+#=============================================================================
def get_command_class(opts, name):
return opts['cmdclass'].get(name) or Distribution().get_command_class(name)
@@ -52,6 +52,6 @@ def stamp_distutils_output(opts, version):
stamp_source(base_dir, version, self.dry_run)
opts['cmdclass']['sdist'] = sdist
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/apache.py b/passlib/apache.py
index e985667..8497ca2 100644
--- a/passlib/apache.py
+++ b/passlib/apache.py
@@ -1,33 +1,32 @@
"""passlib.apache - apache password support"""
# XXX: relocate this to passlib.ext.apache?
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
from hashlib import md5
import logging; log = logging.getLogger(__name__)
import os
import sys
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.context import CryptContext
from passlib.exc import ExpectedStringError
from passlib.hash import htdigest
from passlib.utils import consteq, render_bytes, to_bytes, deprecated_method, is_ascii_codec
from passlib.utils.compat import b, bytes, join_bytes, str_to_bascii, u, \
unicode, BytesIO, iteritems, imap, PY3
-#pkg
-#local
+# local
__all__ = [
'HtpasswdFile',
'HtdigestFile',
]
-#=========================================================
+#=============================================================================
# constants & support
-#=========================================================
+#=============================================================================
_UNSET = object()
_BCOLON = b(":")
@@ -35,9 +34,9 @@ _BCOLON = b(":")
# byte values that aren't allowed in fields.
_INVALID_FIELD_CHARS = b(":\n\r\t\x00")
-#=========================================================
+#=============================================================================
# backport of OrderedDict for PY2.5
-#=========================================================
+#=============================================================================
try:
from collections import OrderedDict
except ImportError:
@@ -69,14 +68,14 @@ except ImportError:
# these aren't used or implemented, so disabling them for safety.
update = pop = popitem = clear = keys = iterkeys = None
-#=========================================================
-#common helpers
-#=========================================================
+#=============================================================================
+# common helpers
+#=============================================================================
class _CommonFile(object):
"""common framework for HtpasswdFile & HtdigestFile"""
- #=======================================================================
+ #===================================================================
# instance attrs
- #=======================================================================
+ #===================================================================
# charset encoding used by file (defaults to utf-8)
encoding = None
@@ -96,9 +95,9 @@ class _CommonFile(object):
# (e.g. user => hash for Htpasswd)
_records = None
- #=======================================================================
+ #===================================================================
# alt constuctors
- #=======================================================================
+ #===================================================================
@classmethod
def from_string(cls, data, **kwds):
"""create new object from raw string.
@@ -131,9 +130,9 @@ class _CommonFile(object):
self.load(path)
return self
- #=======================================================================
+ #===================================================================
# init
- #=======================================================================
+ #===================================================================
def __init__(self, path=None, new=False, autoload=True, autosave=False,
encoding="utf-8", return_unicode=PY3,
):
@@ -192,9 +191,9 @@ class _CommonFile(object):
"modify time when last loaded (if bound to a local file)"
return self._mtime
- #=======================================================================
+ #===================================================================
# loading
- #=======================================================================
+ #===================================================================
def load_if_changed(self):
"""Reload from ``self.path`` only if file has changed since last load"""
if not self._path:
@@ -267,9 +266,9 @@ class _CommonFile(object):
"parse line of file into (key, value) pair"
raise NotImplementedError("should be implemented in subclass")
- #=======================================================================
+ #===================================================================
# saving
- #=======================================================================
+ #===================================================================
def _autosave(self):
"subclass helper to call save() after any changes"
if self.autosave and self._path:
@@ -301,9 +300,9 @@ class _CommonFile(object):
"given key/value pair, encode as line of file"
raise NotImplementedError("should be implemented in subclass")
- #=======================================================================
+ #===================================================================
# field encoding
- #=======================================================================
+ #===================================================================
def _encode_user(self, user):
"user-specific wrapper for _encode_field()"
return self._encode_field(user, "user")
@@ -363,13 +362,13 @@ class _CommonFile(object):
# platforms supporting the 'plaintext' scheme. these classes don't currently
# check for this.
- #=======================================================================
+ #===================================================================
# eoc
- #=======================================================================
+ #===================================================================
-#=========================================================
-#htpasswd editing
-#=========================================================
+#=============================================================================
+# htpasswd editing
+#=============================================================================
# FIXME: apr_md5_crypt technically the default only for windows, netware and tpf.
# TODO: find out if htpasswd's "crypt" mode is a crypt() *call* or just des_crypt implementation.
@@ -528,16 +527,16 @@ class HtpasswdFile(_CommonFile):
any user name contains a forbidden character (one of ``:\\r\\n\\t\\x00``),
or is longer than 255 characters.
"""
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
# NOTE: _records map stores <user> for the key, and <hash> for the value,
# both in bytes which use self.encoding
- #=========================================================
+ #===================================================================
# init & serialization
- #=========================================================
+ #===================================================================
def __init__(self, path=None, default_scheme=None, context=htpasswd_context,
**kwds):
if 'default' in kwds:
@@ -562,9 +561,9 @@ class HtpasswdFile(_CommonFile):
def _render_record(self, user, hash):
return render_bytes("%s:%s\n", user, hash)
- #=========================================================
+ #===================================================================
# public methods
- #=========================================================
+ #===================================================================
def users(self):
"Return list of all users in database"
@@ -677,13 +676,13 @@ class HtpasswdFile(_CommonFile):
"verify password for user"
return self.check_password(user, password)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
-#htdigest editing
-#=========================================================
+#=============================================================================
+# htdigest editing
+#=============================================================================
class HtdigestFile(_CommonFile):
"""class for reading & writing Htdigest files.
@@ -816,9 +815,9 @@ class HtdigestFile(_CommonFile):
any user name or realm contains a forbidden character (one of ``:\\r\\n\\t\\x00``),
or is longer than 255 characters.
"""
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
# NOTE: _records map stores (<user>,<realm>) for the key,
# and <hash> as the value, all as <self.encoding> bytes.
@@ -830,9 +829,9 @@ class HtdigestFile(_CommonFile):
# is provided to a method call. otherwise realm is always required.
default_realm = None
- #=========================================================
+ #===================================================================
# init & serialization
- #=========================================================
+ #===================================================================
def __init__(self, path=None, default_realm=None, **kwds):
self.default_realm = default_realm
super(HtdigestFile, self).__init__(path, **kwds)
@@ -858,9 +857,9 @@ class HtdigestFile(_CommonFile):
"or set the default_realm attribute")
return self._encode_field(realm, "realm")
- #=========================================================
+ #===================================================================
# public methods
- #=========================================================
+ #===================================================================
def realms(self):
"""Return list of all realms in database"""
@@ -1029,10 +1028,10 @@ class HtdigestFile(_CommonFile):
"verify password for user"
return self.check_password(user, realm, password)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/apps.py b/passlib/apps.py
index f740c90..0afb73a 100644
--- a/passlib/apps.py
+++ b/passlib/apps.py
@@ -1,17 +1,16 @@
"""passlib.apps"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import logging; log = logging.getLogger(__name__)
from itertools import chain
-#site
-#libs
+# site
+# pkg
from passlib import hash
from passlib.context import LazyCryptContext
from passlib.utils import sys_bits
-#pkg
-#local
+# local
__all__ = [
'custom_app_context',
'django_context',
@@ -22,9 +21,9 @@ __all__ = [
'postgres_context',
]
-#=========================================================
+#=============================================================================
# master containing all identifiable hashes
-#=========================================================
+#=============================================================================
def _load_master_config():
from passlib.registry import list_crypt_handlers
@@ -66,29 +65,29 @@ def _load_master_config():
return dict(schemes=schemes, default="sha256_crypt")
master_context = LazyCryptContext(onload=_load_master_config)
-#=========================================================
-#for quickly bootstrapping new custom applications
-#=========================================================
+#=============================================================================
+# for quickly bootstrapping new custom applications
+#=============================================================================
custom_app_context = LazyCryptContext(
- #choose some reasonbly strong schemes
+ # choose some reasonbly strong schemes
schemes=["sha512_crypt", "sha256_crypt"],
- #set some useful global options
+ # set some useful global options
default="sha256_crypt" if sys_bits < 64 else "sha512_crypt",
all__vary_rounds = 0.1,
- #set a good starting point for rounds selection
+ # set a good starting point for rounds selection
sha512_crypt__min_rounds = 60000,
sha256_crypt__min_rounds = 80000,
- #if the admin user category is selected, make a much stronger hash,
+ # if the admin user category is selected, make a much stronger hash,
admin__sha512_crypt__min_rounds = 120000,
admin__sha256_crypt__min_rounds = 160000,
)
-#=========================================================
-#django
-#=========================================================
+#=============================================================================
+# django
+#=============================================================================
_django10_schemes = [
"django_salted_sha1", "django_salted_md5", "django_des_crypt",
"hex_md5", "django_disabled",
@@ -109,17 +108,17 @@ django14_context = LazyCryptContext(
# this will always point to latest version
django_context = django14_context
-#=========================================================
-#ldap
-#=========================================================
+#=============================================================================
+# ldap
+#=============================================================================
std_ldap_schemes = ["ldap_salted_sha1", "ldap_salted_md5",
"ldap_sha1", "ldap_md5",
"ldap_plaintext" ]
-#create context with all std ldap schemes EXCEPT crypt
+# create context with all std ldap schemes EXCEPT crypt
ldap_nocrypt_context = LazyCryptContext(std_ldap_schemes)
-#create context with all possible std ldap + ldap crypt schemes
+# create context with all possible std ldap + ldap crypt schemes
def _iter_ldap_crypt_schemes():
from passlib.utils import unix_crypt_schemes
return ('ldap_' + name for name in unix_crypt_schemes)
@@ -129,28 +128,28 @@ def _iter_ldap_schemes():
return chain(std_ldap_schemes, _iter_ldap_crypt_schemes())
ldap_context = LazyCryptContext(_iter_ldap_schemes())
-###create context with all std ldap schemes + crypt schemes for localhost
+### create context with all std ldap schemes + crypt schemes for localhost
##def _iter_host_ldap_schemes():
## "helper which iterates over supported std ldap schemes"
## from passlib.handlers.ldap_digests import get_host_ldap_crypt_schemes
## return chain(std_ldap_schemes, get_host_ldap_crypt_schemes())
##ldap_host_context = LazyCryptContext(_iter_host_ldap_schemes())
-#=========================================================
-#mysql
-#=========================================================
+#=============================================================================
+# mysql
+#=============================================================================
mysql3_context = LazyCryptContext(["mysql323"])
mysql4_context = LazyCryptContext(["mysql41", "mysql323"], deprecated="mysql323")
-mysql_context = mysql4_context #tracks latest mysql version supported
+mysql_context = mysql4_context # tracks latest mysql version supported
-#=========================================================
-#postgres
-#=========================================================
+#=============================================================================
+# postgres
+#=============================================================================
postgres_context = LazyCryptContext(["postgres_md5"])
-#=========================================================
-#phpass & variants
-#=========================================================
+#=============================================================================
+# phpass & variants
+#=============================================================================
def _create_phpass_policy(**kwds):
"helper to choose default alg based on bcrypt availability"
kwds['default'] = 'bcrypt' if hash.bcrypt.has_backend() else 'phpass'
@@ -163,16 +162,16 @@ phpass_context = LazyCryptContext(
phpbb3_context = LazyCryptContext(["phpass"], phpass__ident="H")
-#TODO: support the drupal phpass variants (see phpass homepage)
+# TODO: support the drupal phpass variants (see phpass homepage)
-#=========================================================
-#roundup
-#=========================================================
+#=============================================================================
+# roundup
+#=============================================================================
_std_roundup_schemes = [ "ldap_hex_sha1", "ldap_hex_md5", "ldap_des_crypt", "roundup_plaintext" ]
roundup10_context = LazyCryptContext(_std_roundup_schemes)
-#NOTE: 'roundup15' really applies to roundup 1.4.17+
+# NOTE: 'roundup15' really applies to roundup 1.4.17+
roundup_context = roundup15_context = LazyCryptContext(
schemes=_std_roundup_schemes + [ "ldap_pbkdf2_sha1" ],
deprecated=_std_roundup_schemes,
@@ -180,6 +179,6 @@ roundup_context = roundup15_context = LazyCryptContext(
ldap_pbkdf2_sha1__default_rounds = 10000,
)
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/context.py b/passlib/context.py
index 867add6..84372dc 100644
--- a/passlib/context.py
+++ b/passlib/context.py
@@ -1,9 +1,9 @@
"""passlib.context - CryptContext implementation"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
from functools import update_wrapper
import inspect
import re
@@ -14,8 +14,8 @@ import os
import re
from time import sleep
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.exc import PasslibConfigWarning, ExpectedStringError, ExpectedTypeError
from passlib.registry import get_crypt_handler, _validate_handler_name
from passlib.utils import rng, tick, to_bytes, \
@@ -23,17 +23,16 @@ from passlib.utils import rng, tick, to_bytes, \
from passlib.utils.compat import bytes, iteritems, num_types, \
PY2, PY3, PY_MIN_32, unicode, SafeConfigParser, \
NativeStringIO, BytesIO, base_string_types
-#pkg
-#local
+# local
__all__ = [
'CryptContext',
'LazyCryptContext',
'CryptPolicy',
]
-#=========================================================
+#=============================================================================
# support
-#=========================================================
+#=============================================================================
# private object to detect unset params
_UNSET = object()
@@ -68,9 +67,9 @@ def _is_handler_registered(handler):
"""detect if handler is registered or a custom handler"""
return get_crypt_handler(handler.name, None) is handler
-#=========================================================
+#=============================================================================
# crypt policy
-#=========================================================
+#=============================================================================
_preamble = ("The CryptPolicy class has been deprecated as of "
"Passlib 1.6, and will be removed in Passlib 1.8. ")
@@ -132,9 +131,9 @@ class CryptPolicy(object):
.. deprecated:: 1.6
"""
- #=========================================================
- #class methods
- #=========================================================
+ #===================================================================
+ # class methods
+ #===================================================================
@classmethod
def from_path(cls, path, section="passlib", encoding="utf-8"):
"""create a CryptPolicy instance from a local file.
@@ -276,9 +275,9 @@ class CryptPolicy(object):
sources.append(kwds)
return CryptPolicy.from_sources(sources, _warn=False)
- #=========================================================
- #instance attrs
- #=========================================================
+ #===================================================================
+ # instance attrs
+ #===================================================================
# internal CryptContext we're wrapping to handle everything
# until this class is removed.
@@ -288,9 +287,9 @@ class CryptPolicy(object):
# attribute, rather than one created independantly by the application.
_stub_policy = False
- #=========================================================
+ #===================================================================
# init
- #=========================================================
+ #===================================================================
def __init__(self, *args, **kwds):
context = kwds.pop("_internal_context", None)
if context:
@@ -313,9 +312,9 @@ class CryptPolicy(object):
DeprecationWarning, stacklevel=2)
self._context = CryptContext(**kwds)
- #=========================================================
+ #===================================================================
# public interface for examining options
- #=========================================================
+ #===================================================================
def has_schemes(self):
"""return True if policy defines *any* schemes for use.
@@ -457,9 +456,9 @@ class CryptPolicy(object):
name = name.name
return self._context._is_deprecated_scheme(name, category)
- #=========================================================
+ #===================================================================
# serialization
- #=========================================================
+ #===================================================================
def iter_config(self, ini=False, resolve=False):
"""iterate over key/value pairs representing the policy object.
@@ -561,13 +560,13 @@ class CryptPolicy(object):
out = out.encode(encoding)
return out
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# _CryptRecord helper class
-#=========================================================
+#=============================================================================
class _CryptRecord(object):
"""wraps a handler and automatically applies various options.
@@ -578,9 +577,9 @@ class _CryptRecord(object):
the particular configuration.
"""
- #================================================================
+ #===================================================================
# instance attrs
- #================================================================
+ #===================================================================
# informational attrs
handler = None # handler instance this is wrapping
@@ -590,8 +589,8 @@ class _CryptRecord(object):
# rounds management - filled in by _init_rounds_options()
_has_rounds_options = False # if _has_rounds_bounds OR _generate_rounds is set
_has_rounds_bounds = False # if either min_rounds or max_rounds set
- _min_rounds = None #: minimum rounds allowed by policy, or None
- _max_rounds = None #: maximum rounds allowed by policy, or None
+ _min_rounds = None # minimum rounds allowed by policy, or None
+ _max_rounds = None # maximum rounds allowed by policy, or None
_generate_rounds = None # rounds generation function, or None
# encrypt()/genconfig() attrs
@@ -608,9 +607,9 @@ class _CryptRecord(object):
identify = None
genhash = None
- #================================================================
+ #===================================================================
# init
- #================================================================
+ #===================================================================
def __init__(self, handler, category=None, deprecated=False,
min_rounds=None, max_rounds=None, default_rounds=None,
vary_rounds=None, min_verify_time=None,
@@ -634,9 +633,9 @@ class _CryptRecord(object):
self.identify = handler.identify
self.genhash = handler.genhash
- #================================================================
+ #===================================================================
# virtual attrs
- #================================================================
+ #===================================================================
@property
def scheme(self):
return self.handler.name
@@ -654,9 +653,9 @@ class _CryptRecord(object):
def __repr__(self): # pragma: no cover -- debugging
return "<_CryptRecord 0x%x for %s>" % (id(self), self._errprefix)
- #================================================================
+ #===================================================================
# rounds generation & limits - used by encrypt & deprecation code
- #================================================================
+ #===================================================================
def _init_rounds_options(self, mn, mx, df, vr):
"parse options and compile efficient generate_rounds function"
#----------------------------------------------------
@@ -796,9 +795,9 @@ class _CryptRecord(object):
self._has_rounds_options = True
- #================================================================
+ #===================================================================
# encrypt() / genconfig()
- #================================================================
+ #===================================================================
def _init_encrypt_and_genconfig(self):
"initialize genconfig/encrypt wrapper methods"
settings = self.settings
@@ -829,7 +828,7 @@ class _CryptRecord(object):
def _prepare_settings(self, kwds):
"add default values to settings for encrypt & genconfig"
- #load in default values for any settings
+ # load in default values for any settings
if kwds:
for k,v in iteritems(self.settings):
if k not in kwds:
@@ -863,9 +862,9 @@ class _CryptRecord(object):
rounds = mx
kwds['rounds'] = rounds
- #================================================================
+ #===================================================================
# verify()
- #================================================================
+ #===================================================================
# TODO: once min_verify_time is removed, this will just be a clone
# of handler.verify()
@@ -897,9 +896,9 @@ class _CryptRecord(object):
(self.scheme, mvt, end-start), PasslibConfigWarning)
return False
- #================================================================
+ #===================================================================
# needs_update()
- #================================================================
+ #===================================================================
def _init_needs_update(self):
"""initialize state for needs_update()"""
# if handler has been deprecated, replace wrapper and skip other checks
@@ -958,44 +957,44 @@ class _CryptRecord(object):
return False
- #================================================================
+ #===================================================================
# eoc
- #================================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# _CryptConfig helper class
-#=========================================================
+#=============================================================================
class _CryptConfig(object):
"""parses, validates, and stores CryptContext config
-
+
this is a helper used internally by CryptContext to handle
parsing, validation, and serialization of it's config options.
split out from the main class, but not made public since
that just complicates interface too much (c.f. CryptPolicy)
-
+
:arg source: config as dict mapping ``(cat,scheme,option) -> value``
- """
+ """
#===================================================================
# instance attrs
#===================================================================
-
+
# triple-nested dict which maps scheme -> category -> key -> value,
# storing all hash-specific options
_scheme_options = None
-
+
# double-nested dict which maps key -> category -> value
# storing all CryptContext options
_context_options = None
# tuple of handler objects
handlers = None
-
+
# tuple of scheme objects in same order as handlers
schemes = None
-
+
# tuple of categories in alphabetical order (not including None)
categories = None
-
+
# dict mapping category -> default scheme
_default_schemes = None
@@ -1008,13 +1007,13 @@ class _CryptConfig(object):
#===================================================================
# constructor
- #===================================================================
+ #===================================================================
def __init__(self, source):
self._init_scheme_list(source.get((None,None,"schemes")))
self._init_options(source)
self._init_default_schemes()
self._init_records()
-
+
def _init_scheme_list(self, data):
"""initialize .handlers and .schemes attributes"""
handlers = []
@@ -1049,11 +1048,11 @@ class _CryptConfig(object):
#===================================================================
# lowlevel options
#===================================================================
-
- #-------------------------------------------------------------------
+
+ #---------------------------------------------------------------
# init lowlevel option storage
- #-------------------------------------------------------------------
- def _init_options(self, source):
+ #---------------------------------------------------------------
+ def _init_options(self, source):
"""load config dict into internal representation,
and init .categories attr
"""
@@ -1063,14 +1062,14 @@ class _CryptConfig(object):
self._scheme_options = scheme_options = {}
self._context_options = context_options = {}
categories = set()
-
+
# load source config into internal storage
for (cat, scheme, key), value in iteritems(source):
categories.add(cat)
if scheme:
# normalize scheme option
key, value = norm_scheme_option(key, value)
-
+
# store in scheme_options
# map structure: scheme_options[scheme][category][key] = value
try:
@@ -1088,9 +1087,9 @@ class _CryptConfig(object):
# normalize context option
if cat and key == "schemes":
raise KeyError("'schemes' context option is not allowed "
- "per category")
+ "per category")
key, value = norm_context_option(key, value)
-
+
# store in context_options
# map structure: context_options[key][category] = value
try:
@@ -1100,7 +1099,7 @@ class _CryptConfig(object):
else:
category_map[cat] = value
- # store list of configured categories
+ # store list of configured categories
categories.discard(None)
self.categories = tuple(sorted(categories))
@@ -1120,7 +1119,7 @@ class _CryptConfig(object):
if func:
value = func(value)
return key, value
-
+
def _norm_context_option(self, key, value):
schemes = self.schemes
if key == "default":
@@ -1156,10 +1155,10 @@ class _CryptConfig(object):
elif key != "schemes":
raise KeyError("unknown CryptContext keyword: %r" % (key,))
return key, value
-
- #-------------------------------------------------------------------
+
+ #---------------------------------------------------------------
# reading context options
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
def get_context_optionmap(self, key, _default={}):
"""return dict mapping category->value for specific context option.
(treat retval as readonly).
@@ -1184,10 +1183,10 @@ class _CryptConfig(object):
if value is None or alt != value:
return alt, True
return value, False
-
- #-------------------------------------------------------------------
+
+ #---------------------------------------------------------------
# reading scheme options
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
def _get_scheme_optionmap(self, scheme, category, default={}):
"""return all options for (scheme,category) combination
(treat return as readonly)
@@ -1196,45 +1195,45 @@ class _CryptConfig(object):
return self._scheme_options[scheme][category]
except KeyError:
return default
-
+
def get_scheme_options_with_flag(self, scheme, category):
"""return composite dict of all options set for scheme.
includes options inherited from 'all' and from default category.
result can be modified.
returns (kwds, has_cat_specific_options)
- """
+ """
# start out with copy of global options
get_optionmap = self._get_scheme_optionmap
kwds = get_optionmap("all", None).copy()
has_cat_options = False
-
+
# add in category-specific global options
if category:
defkwds = kwds.copy() # <-- used to detect category-specific options
kwds.update(get_optionmap("all", category))
-
+
# add in default options for scheme
other = get_optionmap(scheme, None)
kwds.update(other)
-
+
# load category-specific options for scheme
if category:
defkwds.update(other)
kwds.update(get_optionmap(scheme, category))
-
+
# compare default category options to see if there's anything
# category-specific
if kwds != defkwds:
has_cat_options = True
-
+
return kwds, has_cat_options
-
+
#===================================================================
# deprecated & default schemes
#===================================================================
def _init_default_schemes(self):
"""initialize maps containing default scheme for each category.
-
+
have to do this after _init_options(), since the default scheme
is affected by the list of deprecated schemes.
"""
@@ -1258,7 +1257,7 @@ class _CryptConfig(object):
raise ValueError("must have at least one non-deprecated scheme")
elif default in deps:
raise ValueError("default scheme cannot be deprecated")
-
+
# figure out per-category default schemes,
for cat in self.categories:
cdeps = dep_map.get(cat, deps)
@@ -1270,7 +1269,7 @@ class _CryptConfig(object):
break
else:
raise ValueError("must have at least one non-deprecated "
- "scheme for %r category" % cat)
+ "scheme for %r category" % cat)
elif cdefault in cdeps:
raise ValueError("default scheme for %r category "
"cannot be deprecated" % cat)
@@ -1286,7 +1285,7 @@ class _CryptConfig(object):
raise KeyError("no hash schemes configured for this "
"CryptContext instance")
return defaults[None]
-
+
def is_deprecated_with_flag(self, scheme, category):
"is scheme deprecated under particular category?"
depmap = self.get_context_optionmap("deprecated")
@@ -1311,7 +1310,7 @@ class _CryptConfig(object):
def _init_records(self):
# NOTE: this step handles final validation of settings,
# checking for violatiions against handler's internal invariants.
- # this is why we create all the records now,
+ # this is why we create all the records now,
# so CryptContext throws error immediately rather than later.
self._record_lists = {}
records = self._records = {}
@@ -1329,7 +1328,7 @@ class _CryptConfig(object):
# will automatically use the default category's record.
# NOTE: default records for specific category stored under the
# key (None,category); these are populated on-demand by get_record().
-
+
def _get_record_options_with_flag(self, scheme, category):
"""return composite dict of options for given scheme + category.
@@ -1345,31 +1344,31 @@ class _CryptConfig(object):
the options dict includes all the scheme-specific settings,
as well as optional *deprecated* and *min_verify_time* keywords.
"""
- # get scheme options
+ # get scheme options
kwds, has_cat_options = self.get_scheme_options_with_flag(scheme, category)
-
+
# throw in deprecated flag
value, not_inherited = self.is_deprecated_with_flag(scheme, category)
if value:
kwds['deprecated'] = True
if not_inherited:
has_cat_options = True
-
+
# add in min_verify_time setting from context
value, not_inherited = self.get_context_option_with_flag(category, "min_verify_time")
if value:
kwds['min_verify_time'] = value
if not_inherited:
has_cat_options = True
-
+
return kwds, has_cat_options
-
+
def get_record(self, scheme, category):
"return record for specific scheme & category (cached)"
# NOTE: this is part of the critical path shared by
# all of CryptContext's PasswordHash methods,
# hence all the caching and error checking.
-
+
# quick lookup in cache
try:
return self._records[scheme, category]
@@ -1409,7 +1408,7 @@ class _CryptConfig(object):
def _get_record_list(self, category=None):
"""return list of records for category (cached)
-
+
this is an internal helper used only by identify_record()
"""
# type check of category - handled by _get_record()
@@ -1417,7 +1416,7 @@ class _CryptConfig(object):
try:
return self._record_lists[category]
except KeyError:
- pass
+ pass
# cache miss - build list from scratch
value = self._record_lists[category] = [
self.get_record(scheme, category)
@@ -1435,7 +1434,7 @@ class _CryptConfig(object):
# about this in future, but for now only hashes with
# unique identifiers will work properly in a CryptContext.
# XXX: if all handlers have a unique prefix (e.g. all are MCF / LDAP),
- # could use dict-lookup to speed up this search.
+ # could use dict-lookup to speed up this search.
if not isinstance(hash, base_string_types):
raise ExpectedStringError(hash, "hash")
# type check of category - handled by _get_record_list()
@@ -1499,14 +1498,14 @@ class _CryptConfig(object):
else:
for key in sorted(kwds):
yield (cat, scheme, key), kwds[key]
-
+
#===================================================================
# eoc
#===================================================================
-
-#=========================================================
+
+#=============================================================================
# main CryptContext class
-#=========================================================
+#=============================================================================
class CryptContext(object):
"""Helper for encrypting passwords using different algorithms.
@@ -1530,12 +1529,12 @@ class CryptContext(object):
# to restrict what the app OR the config can use.
#===================================================================
- #instance attrs
+ # instance attrs
#===================================================================
# _CryptConfig instance holding current parsed config
_config = None
-
+
# copy of _config methods, stored in CryptContext instance for speed.
_get_record = None
_identify_record = None
@@ -1656,7 +1655,7 @@ class CryptContext(object):
"""
# XXX: it would be faster to store ref to self._config,
# but don't want to share config objects til sure
- # can rely on them being immutable.
+ # can rely on them being immutable.
other = CryptContext(_autoload=False)
other.load(self)
if kwds:
@@ -1672,7 +1671,7 @@ class CryptContext(object):
return self.copy(**kwds)
#===================================================================
- #init
+ # init
#===================================================================
def __init__(self, schemes=None,
# keyword only...
@@ -1881,7 +1880,7 @@ class CryptContext(object):
# otherwise overlay source on top of existing config
tmp = source
source = dict(self._config.iter_config(resolve=True))
- source.update(tmp)
+ source.update(tmp)
#-----------------------------------------------------------
# compile into _CryptConfig instance, and update state
@@ -1890,7 +1889,7 @@ class CryptContext(object):
self._config = config
self._get_record = config.get_record
self._identify_record = config.identify_record
-
+
@staticmethod
def _parse_config_key(ckey):
"""helper used to parse ``cat__scheme__option`` keys into a tuple"""
@@ -1946,7 +1945,7 @@ class CryptContext(object):
# XXX: make this public? even just as flag to load?
# FIXME: this function suffered some bitrot in 1.6.1,
- # will need to be updated before works again.
+ # will need to be updated before works again.
##def _simplify(self):
## "helper to remove redundant/unused options"
## # don't do anything if no schemes are defined
@@ -2040,7 +2039,7 @@ class CryptContext(object):
# type check of category - handled by _get_record()
record = self._get_record(None, category)
return record.handler if resolve else record.scheme
-
+
# XXX: need to decide if exposing this would be useful in any way
##def categories(self):
## """return user-categories with algorithm-specific options in this CryptContext.
@@ -2123,7 +2122,7 @@ class CryptContext(object):
assert isinstance(value, str), \
"expected string for key: %r %r" % (key, value)
- #escape any percent signs.
+ # escape any percent signs.
return value.replace("%", "%%")
def to_dict(self, resolve=False):
@@ -2237,11 +2236,11 @@ class CryptContext(object):
# The record objects are cached inside the _CryptConfig
# instance stored in self._config, and are retreived
# via get_record() and identify_record().
- #
+ #
# _get_record() and _identify_record() are references
# to _config methods of the same name,
# stored in CryptContext for speed.
-
+
def _get_or_identify_record(self, hash, scheme=None, category=None):
"return record based on scheme, or failing that, by identifying hash"
if scheme:
@@ -2310,7 +2309,7 @@ class CryptContext(object):
.. deprecated:: 1.6
use :meth:`needs_update` instead.
"""
- # FIXME: needs deprecation warning.
+ # FIXME: needs deprecation warning.
return self.needs_update(hash, scheme, category)
def genconfig(self, scheme=None, category=None, **settings):
@@ -2596,9 +2595,9 @@ class CryptContext(object):
else:
return True, None
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
class LazyCryptContext(CryptContext):
"""CryptContext subclass which doesn't load handlers until needed.
@@ -2681,6 +2680,6 @@ class LazyCryptContext(CryptContext):
self._lazy_init()
return object.__getattribute__(self, attr)
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/exc.py b/passlib/exc.py
index f117bbe..1d3538b 100644
--- a/passlib/exc.py
+++ b/passlib/exc.py
@@ -1,7 +1,7 @@
"""passlib.exc -- exceptions & warnings raised by passlib"""
-#==========================================================================
+#=============================================================================
# exceptions
-#==========================================================================
+#=============================================================================
class MissingBackendError(RuntimeError):
"""Error raised if multi-backend handler has no available backends;
or if specifically requested backend is not available.
@@ -24,7 +24,7 @@ class PasswordSizeError(ValueError):
password is provided to an application. Because of this, Passlib enforces
a maximum size limit, but one which should be *much* larger
than any legitimate password. :exc:`!PasswordSizeError` derives
- from :exc:`!ValueError`.
+ from :exc:`!ValueError`.
.. note::
Applications wishing to use a different limit should set the
@@ -39,9 +39,9 @@ class PasswordSizeError(ValueError):
# this also prevents a glibc crypt segfault issue, detailed here ...
# http://www.openwall.com/lists/oss-security/2011/11/15/1
-#==========================================================================
+#=============================================================================
# warnings
-#==========================================================================
+#=============================================================================
class PasslibWarning(UserWarning):
"""base class for Passlib's user warnings.
@@ -89,7 +89,7 @@ class PasslibSecurityWarning(PasslibWarning):
that might affect security.
"""
-#==========================================================================
+#=============================================================================
# error constructors
#
# note: these functions are used by the hashes in Passlib to raise common
@@ -97,14 +97,14 @@ class PasslibSecurityWarning(PasslibWarning):
# rather than subclasses of ValueError, since the specificity isn't needed
# yet; and who wants to import a bunch of error classes when catching
# ValueError will do?
-#==========================================================================
+#=============================================================================
def _get_name(handler):
return handler.name if handler else "<unnamed>"
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
# generic helpers
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
def type_name(value):
"return pretty-printed string containing name of value's type"
cls = value.__class__
@@ -125,9 +125,9 @@ def ExpectedStringError(value, param):
"error message when param was supposed to be unicode or bytes"
return ExpectedTypeError(value, "unicode or bytes", param)
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
# encrypt/verify parameter errors
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
def MissingDigestError(handler=None):
"raised when verify() method gets passed config string instead of hash"
name = _get_name(handler)
@@ -139,9 +139,9 @@ def NullPasswordError(handler=None):
name = _get_name(handler)
return ValueError("%s does not allow NULL bytes in password" % name)
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
# errors when parsing hashes
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
def InvalidHashError(handler=None):
"error raised if unrecognized hash provided to handler"
return ValueError("not a valid %s hash" % _get_name(handler))
@@ -157,9 +157,9 @@ def ZeroPaddedRoundsError(handler=None):
"error raised if hash was recognized but contained zero-padded rounds field"
return MalformedHashError(handler, "zero-padded rounds")
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
# settings / hash component errors
-#----------------------------------------------------------------
+#------------------------------------------------------------------------
def ChecksumSizeError(handler, raw=False):
"error raised if hash was recognized, but checksum was wrong size"
# TODO: if handler.use_defaults is set, this came from app-provided value,
@@ -169,6 +169,6 @@ def ChecksumSizeError(handler, raw=False):
reason = "checksum must be exactly %d %s" % (checksum_size, unit)
return MalformedHashError(handler, reason)
-#==========================================================================
+#=============================================================================
# eof
-#==========================================================================
+#=============================================================================
diff --git a/passlib/ext/django/models.py b/passlib/ext/django/models.py
index 55bb4c6..e3938aa 100644
--- a/passlib/ext/django/models.py
+++ b/passlib/ext/django/models.py
@@ -1,7 +1,7 @@
"""passlib.ext.django.models -- monkeypatch django hashing framework"""
-#===================================================================
-#imports
-#===================================================================
+#=============================================================================
+# imports
+#=============================================================================
# core
import logging; log = logging.getLogger(__name__)
from warnings import warn
@@ -17,9 +17,9 @@ from passlib.utils.compat import callable, unicode, bytes
# local
__all__ = ["password_context"]
-#===================================================================
+#=============================================================================
# global attrs
-#===================================================================
+#=============================================================================
# the context object which this patches contrib.auth to use for password hashing.
# configuration controlled by ``settings.PASSLIB_CONFIG``.
@@ -42,9 +42,9 @@ _manager = _PatchManager(log=logging.getLogger(__name__ + "._manager"))
# patch status
_patched = False
-#===================================================================
+#=============================================================================
# applying & removing the patches
-#===================================================================
+#=============================================================================
def _apply_patch():
"""monkeypatch django's password handling to use ``passlib_context``,
assumes the caller will configure the object.
@@ -216,9 +216,9 @@ def _remove_patch():
log.debug("django not monkeypatched")
return False
-#===================================================================
+#=============================================================================
# main code
-#===================================================================
+#=============================================================================
def _load():
global _get_category
@@ -276,6 +276,6 @@ except:
_remove_patch()
raise
-#===================================================================
-#eof
-#===================================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/ext/django/utils.py b/passlib/ext/django/utils.py
index 72e50ae..098dbe4 100644
--- a/passlib/ext/django/utils.py
+++ b/passlib/ext/django/utils.py
@@ -1,7 +1,7 @@
"""passlib.ext.django.utils - helper functions used by this plugin"""
-#===================================================================
-#imports
-#===================================================================
+#=============================================================================
+# imports
+#=============================================================================
# core
import logging; log = logging.getLogger(__name__)
from weakref import WeakKeyDictionary
@@ -25,9 +25,9 @@ __all__ = [
"get_passlib_hasher",
]
-#===================================================================
+#=============================================================================
# default policies
-#===================================================================
+#=============================================================================
def get_preset_config(name):
"""Returns configuration string for one of the preset strings
supported by the ``PASSLIB_CONFIG`` setting.
@@ -92,9 +92,9 @@ superuser__sha512_crypt__default_rounds = 120000
superuser__django_pbkdf2_sha256__default_rounds = 15000
"""
-#===================================================================
+#=============================================================================
# translating passlib names <-> hasher names
-#===================================================================
+#=============================================================================
# prefix used to shoehorn passlib's handler names into hasher namespace
# (allows get_hasher() to be meaningfully called even if passlib handler
@@ -129,9 +129,9 @@ def hasher_to_passlib_name(hasher_name):
raise ValueError("can't translate hasher name to passlib name: %r" %
hasher_name)
-#===================================================================
+#=============================================================================
# wrapping passlib handlers as django hashers
-#===================================================================
+#=============================================================================
_FAKE_SALT = "--fake-salt--"
class _HasherWrapper(object):
@@ -229,9 +229,9 @@ def _get_hasher(algorithm):
get_hasher = module._manager.getorig("django.contrib.auth.hashers:get_hasher")
return get_hasher(algorithm)
-#===================================================================
+#=============================================================================
# adapting django hashers -> passlib handlers
-#===================================================================
+#=============================================================================
# TODO: this code probably halfway works, mainly just needs
# a routine to read HASHERS and PREFERRED_HASHER.
@@ -322,9 +322,9 @@ def _get_hasher(algorithm):
## register_crypt_handler(handler)
## return handler
-#===================================================================
+#=============================================================================
# monkeypatch helpers
-#===================================================================
+#=============================================================================
# private singleton indicating lack-of-value
_UNSET = object()
@@ -465,6 +465,6 @@ class _PatchManager(object):
# eoc
#===================================================================
-#===================================================================
-#eof
-#===================================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py
index 3f95d16..5b37dc9 100644
--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -7,40 +7,39 @@ TODO:
* deal with lack of PY3-compatibile c-ext implementation
"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement, absolute_import
-#core
+# core
import os
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
+# site
try:
from bcrypt import hashpw as pybcrypt_hashpw
-except ImportError: #pragma: no cover
+except ImportError: # pragma: no cover
pybcrypt_hashpw = None
try:
from bcryptor.engine import Engine as bcryptor_engine
-except ImportError: #pragma: no cover
+except ImportError: # pragma: no cover
bcryptor_engine = None
-#libs
+# pkg
from passlib.exc import PasslibHashWarning
from passlib.utils import bcrypt64, safe_crypt, repeat_string, \
classproperty, rng, getrandstr, test_crypt
from passlib.utils.compat import bytes, b, u, uascii_to_str, unicode, str_to_uascii
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"bcrypt",
]
-#=========================================================
+#=============================================================================
# support funcs & constants
-#=========================================================
+#=============================================================================
_builtin_bcrypt = None
def _load_builtin():
@@ -54,9 +53,9 @@ IDENT_2X = u("$2x$")
IDENT_2Y = u("$2y$")
_BNULL = b('\x00')
-#=========================================================
+#=============================================================================
# handler
-#=========================================================
+#=============================================================================
class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.GenericHandler):
"""This class implements the BCrypt password hash, and follows the :ref:`password-hash-api`.
@@ -78,10 +77,10 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
:type ident: str
:param ident:
- Specifies which version of the BCrypt algorithm will be used when creating a new hash.
+ Specifies which version of the BCrypt algorithm will be used when creating a new hash.
Typically this option is not needed, as the default (``"2a"``) is usually the correct choice.
- If specified, it must be one of the following:
-
+ If specified, it must be one of the following:
+
* ``"2"`` - the first revision of BCrypt, which suffers from a minor security flaw and is generally not used anymore.
* ``"2a"`` - latest revision of the official BCrypt algorithm, and the current default.
* ``"2y"`` - format specific to the *crypt_blowfish* BCrypt implementation,
@@ -104,9 +103,9 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
for details).
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "bcrypt"
setting_kwds = ("salt", "rounds", "ident")
@@ -121,7 +120,7 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
#--HasSalt--
min_salt_size = max_salt_size = 22
salt_chars = bcrypt64.charmap
- #NOTE: 22nd salt char must be in bcrypt64._padinfo2[1], not full charmap
+ # NOTE: 22nd salt char must be in bcrypt64._padinfo2[1], not full charmap
#--HasRounds--
default_rounds = 12 # current passlib default
@@ -129,9 +128,9 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
max_rounds = 31 # 32-bit integer limit (since real_rounds=1<<rounds)
rounds_cost = "log2"
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
@classmethod
def from_string(cls, hash):
@@ -167,9 +166,9 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
config = u("%s%02d$%s") % (ident, self.rounds, self.salt)
return uascii_to_str(config)
- #=========================================================
+ #===================================================================
# specialized salt generation - fixes passlib issue 25
- #=========================================================
+ #===================================================================
@classmethod
def _bind_needs_update(cls, **settings):
@@ -225,9 +224,9 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
PasslibHashWarning)
return checksum
- #=========================================================
- #primary interface
- #=========================================================
+ #===================================================================
+ # primary interface
+ #===================================================================
backends = ("pybcrypt", "bcryptor", "os_crypt", "builtin")
@classproperty
@@ -276,7 +275,7 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
)
def _calc_checksum_pybcrypt(self, secret):
- #py-bcrypt behavior:
+ # py-bcrypt behavior:
# py2: unicode secret/hash encoded as ascii bytes before use,
# bytes taken as-is; returns ascii bytes.
# py3: not supported (patch submitted)
@@ -290,7 +289,7 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
return str_to_uascii(hash[-31:])
def _calc_checksum_bcryptor(self, secret):
- #bcryptor behavior:
+ # bcryptor behavior:
# py2: unicode secret/hash encoded as ascii bytes before use,
# bytes taken as-is; returns ascii bytes.
# py3: not supported
@@ -323,10 +322,10 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
self.salt.encode("ascii"), self.rounds)
return chk.decode("ascii")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/cisco.py b/passlib/handlers/cisco.py
index 196e38b..b66168e 100644
--- a/passlib/handlers/cisco.py
+++ b/passlib/handlers/cisco.py
@@ -1,28 +1,27 @@
"""passlib.handlers.cisco - Cisco password hashes"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify, unhexlify
from hashlib import md5
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
-#pkg
+# site
+# pkg
from passlib.utils import h64, right_pad_string, to_unicode
from passlib.utils.compat import b, bascii_to_str, bytes, unicode, u, join_byte_values, \
join_byte_elems, byte_elem_value, iter_byte_values, uascii_to_str, str_to_uascii
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
"cisco_pix",
"cisco_type7",
]
-#=========================================================
+#=============================================================================
# cisco pix firewall hash
-#=========================================================
+#=============================================================================
class cisco_pix(uh.HasUserContext, uh.StaticHandler):
"""This class implements the password hash used by Cisco PIX firewalls,
and follows the :ref:`password-hash-api`.
@@ -44,16 +43,16 @@ class cisco_pix(uh.HasUserContext, uh.StaticHandler):
hash passwords which don't have an associated user account
(such as the "enable" password).
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "cisco_pix"
checksum_size = 16
checksum_chars = uh.HASH64_CHARS
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
# XXX: no idea what unicode policy is, but all examples are
@@ -81,13 +80,13 @@ class cisco_pix(uh.HasUserContext, uh.StaticHandler):
# encode using Hash64
return h64.encode_bytes(hash).decode("ascii")
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# type 7
-#=========================================================
+#=============================================================================
class cisco_type7(uh.GenericHandler):
"""This class implements the Type 7 password encoding used by Cisco IOS,
and follows the :ref:`password-hash-api`.
@@ -109,7 +108,7 @@ class cisco_type7(uh.GenericHandler):
and the error can be corrected, a :exc:`~passlib.exc.PasslibHashWarning`
will be issued instead. Correctable errors include
``salt`` values that are out of range.
-
+
.. versionadded:: 1.6
Note that while this class outputs digests in upper-case hexidecimal,
@@ -119,9 +118,9 @@ class cisco_type7(uh.GenericHandler):
.. automethod:: decode
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "cisco_type7"
setting_kwds = ("salt",)
checksum_chars = uh.UPPER_HEX_CHARS
@@ -129,9 +128,9 @@ class cisco_type7(uh.GenericHandler):
min_salt_value = 0
max_salt_value = 52
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def genconfig(cls):
return None
@@ -215,6 +214,6 @@ class cisco_type7(uh.GenericHandler):
for idx, value in enumerate(iter_byte_values(data))
)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/des_crypt.py b/passlib/handlers/des_crypt.py
index d549815..1699e1d 100644
--- a/passlib/handlers/des_crypt.py
+++ b/passlib/handlers/des_crypt.py
@@ -1,19 +1,18 @@
"""passlib.handlers.des_crypt - traditional unix (DES) crypt and variants"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import classproperty, h64, h64big, safe_crypt, test_crypt, to_unicode
from passlib.utils.compat import b, bytes, byte_elem_value, u, uascii_to_str, unicode
from passlib.utils.des import des_encrypt_int_block
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"des_crypt",
"bsdi_crypt",
@@ -21,9 +20,9 @@ __all__ = [
"crypt16",
]
-#=========================================================
+#=============================================================================
# pure-python backend for des_crypt family
-#=========================================================
+#=============================================================================
_BNULL = b('\x00')
def _crypt_secret_to_key(secret):
@@ -52,7 +51,7 @@ def _raw_des_crypt(secret, salt):
# and openbsd does something which creates an invalid hash.
try:
salt_value = h64.decode_int12(salt)
- except ValueError: #pragma: no cover - always caught by class
+ except ValueError: # pragma: no cover - always caught by class
raise ValueError("invalid chars in salt")
# gotta do something - no official policy since this predates unicode
@@ -91,7 +90,7 @@ def _raw_bsdi_crypt(secret, rounds, salt):
# decode salt
try:
salt_value = h64.decode_int24(salt)
- except ValueError: #pragma: no cover - always caught by class
+ except ValueError: # pragma: no cover - always caught by class
raise ValueError("invalid salt")
# gotta do something - no official policy since this predates unicode
@@ -112,9 +111,9 @@ def _raw_bsdi_crypt(secret, rounds, salt):
# run h64 encode on result
return h64big.encode_int64(result)
-#=========================================================
+#=============================================================================
# handlers
-#=========================================================
+#=============================================================================
class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
"""This class implements the des-crypt password hash, and follows the :ref:`password-hash-api`.
@@ -138,9 +137,9 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
#--GenericHandler--
name = "des_crypt"
setting_kwds = ("salt",)
@@ -151,10 +150,10 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
min_salt_size = max_salt_size = 2
salt_chars = uh.HASH64_CHARS
- #=========================================================
+ #===================================================================
# formatting
- #=========================================================
- #FORMAT: 2 chars of H64-encoded salt + 11 chars of H64-encoded checksum
+ #===================================================================
+ # FORMAT: 2 chars of H64-encoded salt + 11 chars of H64-encoded checksum
_hash_regex = re.compile(u(r"""
^
@@ -172,9 +171,9 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
hash = u("%s%s") % (self.salt, self.checksum or u(''))
return uascii_to_str(hash)
- #=========================================================
+ #===================================================================
# backend
- #=========================================================
+ #===================================================================
backends = ("os_crypt", "builtin")
_has_backend_builtin = True
@@ -196,9 +195,9 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
else:
return self._calc_checksum_builtin(secret)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
"""This class implements the BSDi-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -232,9 +231,9 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
:meth:`encrypt` will now issue a warning if an even number of rounds is used
(see :ref:`bsdi-crypt-security-issues` regarding weak DES keys).
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
#--GenericHandler--
name = "bsdi_crypt"
setting_kwds = ("salt", "rounds")
@@ -254,9 +253,9 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
# NOTE: OpenBSD login.conf reports 7250 as minimum allowed rounds,
# but that seems to be an OS policy, not a algorithm limitation.
- #=========================================================
+ #===================================================================
# parsing
- #=========================================================
+ #===================================================================
_hash_regex = re.compile(u(r"""
^
_
@@ -283,9 +282,9 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
self.salt, self.checksum or u(''))
return uascii_to_str(hash)
- #=========================================================
+ #===================================================================
# validation
- #=========================================================
+ #===================================================================
# flag so CryptContext won't generate even rounds.
_avoid_even_rounds = True
@@ -312,9 +311,9 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
rounds = h64.decode_int24(hash[1:5])
return not rounds & 1
- #=========================================================
+ #===================================================================
# backends
- #=========================================================
+ #===================================================================
backends = ("os_crypt", "builtin")
_has_backend_builtin = True
@@ -335,9 +334,9 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
else:
return self._calc_checksum_builtin(secret)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class bigcrypt(uh.HasSalt, uh.GenericHandler):
"""This class implements the BigCrypt password hash, and follows the :ref:`password-hash-api`.
@@ -362,22 +361,22 @@ class bigcrypt(uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
#--GenericHandler--
name = "bigcrypt"
setting_kwds = ("salt",)
checksum_chars = uh.HASH64_CHARS
- #NOTE: checksum chars must be multiple of 11
+ # NOTE: checksum chars must be multiple of 11
#--HasSalt--
min_salt_size = max_salt_size = 2
salt_chars = uh.HASH64_CHARS
- #=========================================================
+ #===================================================================
# internal helpers
- #=========================================================
+ #===================================================================
_hash_regex = re.compile(u(r"""
^
(?P<salt>[./a-z0-9]{2})
@@ -403,9 +402,9 @@ class bigcrypt(uh.HasSalt, uh.GenericHandler):
raise uh.exc.InvalidHashError(self)
return value
- #=========================================================
+ #===================================================================
# backend
- #=========================================================
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
@@ -418,9 +417,9 @@ class bigcrypt(uh.HasSalt, uh.GenericHandler):
idx = next
return chk.decode("ascii")
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class crypt16(uh.HasSalt, uh.GenericHandler):
"""This class implements the crypt16 password hash, and follows the :ref:`password-hash-api`.
@@ -445,9 +444,9 @@ class crypt16(uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
#--GenericHandler--
name = "crypt16"
setting_kwds = ("salt",)
@@ -458,9 +457,9 @@ class crypt16(uh.HasSalt, uh.GenericHandler):
min_salt_size = max_salt_size = 2
salt_chars = uh.HASH64_CHARS
- #=========================================================
+ #===================================================================
# internal helpers
- #=========================================================
+ #===================================================================
_hash_regex = re.compile(u(r"""
^
(?P<salt>[./a-z0-9]{2})
@@ -480,39 +479,39 @@ class crypt16(uh.HasSalt, uh.GenericHandler):
hash = u("%s%s") % (self.salt, self.checksum or u(''))
return uascii_to_str(hash)
- #=========================================================
+ #===================================================================
# backend
- #=========================================================
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
- #parse salt value
+ # parse salt value
try:
salt_value = h64.decode_int12(self.salt.encode("ascii"))
- except ValueError: #pragma: no cover - caught by class
+ except ValueError: # pragma: no cover - caught by class
raise ValueError("invalid chars in salt")
- #convert first 8 byts of secret string into an integer,
+ # convert first 8 byts of secret string into an integer,
key1 = _crypt_secret_to_key(secret)
- #run data through des using input of 0
+ # run data through des using input of 0
result1 = des_encrypt_int_block(key1, 0, salt_value, 20)
- #convert next 8 bytes of secret string into integer (key=0 if secret < 8 chars)
+ # convert next 8 bytes of secret string into integer (key=0 if secret < 8 chars)
key2 = _crypt_secret_to_key(secret[8:16])
- #run data through des using input of 0
+ # run data through des using input of 0
result2 = des_encrypt_int_block(key2, 0, salt_value, 5)
- #done
+ # done
chk = h64big.encode_int64(result1) + h64big.encode_int64(result2)
return chk.decode("ascii")
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/handlers/digests.py b/passlib/handlers/digests.py
index e511e16..f1a21bd 100644
--- a/passlib/handlers/digests.py
+++ b/passlib/handlers/digests.py
@@ -1,20 +1,19 @@
"""passlib.handlers.digests - plain hash digests
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import hashlib
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import to_native_str, to_bytes, render_bytes, consteq
from passlib.utils.compat import bascii_to_str, bytes, unicode, str_to_uascii
import passlib.utils.handlers as uh
from passlib.utils.md4 import md4
-#pkg
-#local
+# local
__all__ = [
"create_hex_hash",
"hex_md4",
@@ -24,21 +23,21 @@ __all__ = [
"hex_sha512",
]
-#=========================================================
-#helpers for hexidecimal hashes
-#=========================================================
+#=============================================================================
+# helpers for hexidecimal hashes
+#=============================================================================
class HexDigestHash(uh.StaticHandler):
"this provides a template for supporting passwords stored as plain hexidecimal hashes"
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
_hash_func = None # hash function to use - filled in by create_hex_hash()
checksum_size = None # filled in by create_hex_hash()
checksum_chars = uh.HEX_CHARS
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.lower()
@@ -48,18 +47,18 @@ class HexDigestHash(uh.StaticHandler):
secret = secret.encode("utf-8")
return str_to_uascii(self._hash_func(secret).hexdigest())
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
def create_hex_hash(hash, digest_name, module=__name__):
- #NOTE: could set digest_name=hash.name for cpython, but not for some other platforms.
+ # NOTE: could set digest_name=hash.name for cpython, but not for some other platforms.
h = hash()
name = "hex_" + digest_name
return type(name, (HexDigestHash,), dict(
name=name,
__module__=module, # so ABCMeta won't clobber it
- _hash_func=staticmethod(hash), #sometimes it's a function, sometimes not. so wrap it.
+ _hash_func=staticmethod(hash), # sometimes it's a function, sometimes not. so wrap it.
checksum_size=h.digest_size*2,
__doc__="""This class implements a plain hexidecimal %s hash, and follows the :ref:`password-hash-api`.
@@ -67,9 +66,9 @@ It supports no optional or contextual keywords.
""" % (digest_name,)
))
-#=========================================================
-#predefined handlers
-#=========================================================
+#=============================================================================
+# predefined handlers
+#=============================================================================
hex_md4 = create_hex_hash(md4, "md4")
hex_md5 = create_hex_hash(hashlib.md5, "md5")
hex_md5.django_name = "unsalted_md5"
@@ -77,9 +76,9 @@ hex_sha1 = create_hex_hash(hashlib.sha1, "sha1")
hex_sha256 = create_hex_hash(hashlib.sha256, "sha256")
hex_sha512 = create_hex_hash(hashlib.sha512, "sha512")
-#=========================================================
+#=============================================================================
# htdigest
-#=========================================================
+#=============================================================================
class htdigest(uh.PasswordHash):
"""htdigest hash function.
@@ -140,6 +139,6 @@ class htdigest(uh.PasswordHash):
cls._norm_hash(config)
return cls.encrypt(secret, user, realm, encoding)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/django.py b/passlib/handlers/django.py
index e8d1ec9..5e67abf 100644
--- a/passlib/handlers/django.py
+++ b/passlib/handlers/django.py
@@ -1,21 +1,20 @@
"""passlib.handlers.django- Django password hash support"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from base64 import b64encode
from hashlib import md5, sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import to_unicode, classproperty
from passlib.utils.compat import b, bytes, str_to_uascii, uascii_to_str, unicode, u
from passlib.utils.pbkdf2 import pbkdf2
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"django_salted_sha1",
"django_salted_md5",
@@ -26,9 +25,9 @@ __all__ = [
"django_disabled",
]
-#=========================================================
+#=============================================================================
# lazy imports & constants
-#=========================================================
+#=============================================================================
des_crypt = None
def _import_des_crypt():
@@ -40,9 +39,9 @@ def _import_des_crypt():
# django 1.4's salt charset
SALT_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
-#=========================================================
+#=============================================================================
# salted hashes
-#=========================================================
+#=============================================================================
class DjangoSaltedHash(uh.HasSalt, uh.GenericHandler):
"""base class providing common code for django hashes"""
# name, ident, checksum_size must be set by subclass.
@@ -277,9 +276,9 @@ class django_pbkdf2_sha1(django_pbkdf2_sha256):
checksum_size = 28 # 20 bytes -> base64
_prf = "hmac-sha1"
-#=========================================================
-#other
-#=========================================================
+#=============================================================================
+# other
+#=============================================================================
class django_des_crypt(uh.HasSalt, uh.GenericHandler):
"""This class implements Django's :class:`des_crypt` wrapper, and follows the :ref:`password-hash-api`.
@@ -373,6 +372,6 @@ class django_disabled(uh.StaticHandler):
raise uh.exc.InvalidHashError(cls)
return False
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/handlers/fshp.py b/passlib/handlers/fshp.py
index fe82415..3ecb7b6 100644
--- a/passlib/handlers/fshp.py
+++ b/passlib/handlers/fshp.py
@@ -1,29 +1,28 @@
"""passlib.handlers.fshp
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from base64 import b64encode, b64decode
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import to_unicode
import passlib.utils.handlers as uh
from passlib.utils.compat import b, bytes, bascii_to_str, iteritems, u,\
unicode
from passlib.utils.pbkdf2 import pbkdf1
-#pkg
-#local
+# local
__all__ = [
'fshp',
]
-#=========================================================
-#sha1-crypt
-#=========================================================
+#=============================================================================
+# sha1-crypt
+#=============================================================================
class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"""This class implements the FSHP password hash, and follows the :ref:`password-hash-api`.
@@ -62,9 +61,9 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "fshp"
setting_kwds = ("salt", "salt_size", "rounds", "variant")
@@ -73,22 +72,22 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
# checksum_size is property() that depends on variant
#--HasRawSalt--
- default_salt_size = 16 #current passlib default, FSHP uses 8
+ default_salt_size = 16 # current passlib default, FSHP uses 8
min_salt_size = 0
max_salt_size = None
#--HasRounds--
# FIXME: should probably use different default rounds
# based on the variant. setting for default variant (sha256) for now.
- default_rounds = 50000 #current passlib default, FSHP uses 4096
- min_rounds = 1 #set by FSHP
+ default_rounds = 50000 # current passlib default, FSHP uses 4096
+ min_rounds = 1 # set by FSHP
max_rounds = 4294967295 # 32-bit integer limit - not set by FSHP
rounds_cost = "linear"
#--variants--
default_variant = 1
_variant_info = {
- #variant: (hash name, digest size)
+ # variant: (hash name, digest size)
0: ("sha1", 20),
1: ("sha256", 32),
2: ("sha384", 48),
@@ -99,14 +98,14 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
[(v[0],k) for k,v in iteritems(_variant_info)]
)
- #=========================================================
- #instance attrs
- #=========================================================
+ #===================================================================
+ # instance attrs
+ #===================================================================
variant = None
- #=========================================================
- #init
- #=========================================================
+ #===================================================================
+ # init
+ #===================================================================
def __init__(self, variant=None, **kwds):
# NOTE: variant must be set first, since it controls checksum size, etc.
self.use_defaults = kwds.get("use_defaults") # load this early
@@ -139,9 +138,9 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
def checksum_size(self):
return self._variant_info[self.variant][1]
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
_hash_regex = re.compile(u(r"""
^
@@ -180,16 +179,16 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
data = bascii_to_str(b64encode(salt+chk))
return "{FSHP%d|%d|%d}%s" % (self.variant, len(salt), self.rounds, data)
- #=========================================================
- #backend
- #=========================================================
+ #===================================================================
+ # backend
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
- #NOTE: for some reason, FSHP uses pbkdf1 with password & salt reversed.
- # this has only a minimal impact on security,
- # but it is worth noting this deviation.
+ # NOTE: for some reason, FSHP uses pbkdf1 with password & salt reversed.
+ # this has only a minimal impact on security,
+ # but it is worth noting this deviation.
return pbkdf1(
secret=self.salt,
salt=secret,
@@ -198,10 +197,10 @@ class fshp(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
hash=self.checksum_alg,
)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/ldap_digests.py b/passlib/handlers/ldap_digests.py
index ed12e86..a25a394 100644
--- a/passlib/handlers/ldap_digests.py
+++ b/passlib/handlers/ldap_digests.py
@@ -1,23 +1,22 @@
"""passlib.handlers.digests - plain hash digests
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from base64 import b64encode, b64decode
from hashlib import md5, sha1
import logging; log = logging.getLogger(__name__)
import re
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.handlers.misc import plaintext
from passlib.utils import to_native_str, unix_crypt_schemes, \
classproperty, to_unicode
from passlib.utils.compat import b, bytes, uascii_to_str, unicode, u
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"ldap_plaintext",
"ldap_md5",
@@ -35,16 +34,16 @@ __all__ = [
"ldap_sha512_crypt",
]
-#=========================================================
-#ldap helpers
-#=========================================================
+#=============================================================================
+# ldap helpers
+#=============================================================================
class _Base64DigestHelper(uh.StaticHandler):
"helper for ldap_md5 / ldap_sha1"
- #XXX: could combine this with hex digests in digests.py
+ # XXX: could combine this with hex digests in digests.py
- ident = None #required - prefix identifier
- _hash_func = None #required - hash function
- _hash_regex = None #required - regexp to recognize hash
+ ident = None # required - prefix identifier
+ _hash_func = None # required - hash function
+ _hash_regex = None # required - regexp to recognize hash
checksum_chars = uh.PADDED_BASE64_CHARS
@classproperty
@@ -63,11 +62,11 @@ class _SaltedBase64DigestHelper(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHand
setting_kwds = ("salt", "salt_size")
checksum_chars = uh.PADDED_BASE64_CHARS
- ident = None #required - prefix identifier
- checksum_size = None #required
- _hash_func = None #required - hash function
- _hash_regex = None #required - regexp to recognize hash
- _stub_checksum = None #required - default checksum to plug in
+ ident = None # required - prefix identifier
+ checksum_size = None # required
+ _hash_func = None # required - hash function
+ _hash_regex = None # required - regexp to recognize hash
+ _stub_checksum = None # required - default checksum to plug in
min_salt_size = max_salt_size = 4
# NOTE: openldap implementation uses 4 byte salt,
@@ -101,9 +100,9 @@ class _SaltedBase64DigestHelper(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHand
secret = secret.encode("utf-8")
return self._hash_func(secret + self.salt).digest()
-#=========================================================
-#implementations
-#=========================================================
+#=============================================================================
+# implementations
+#=============================================================================
class ldap_md5(_Base64DigestHelper):
"""This class stores passwords using LDAP's plain MD5 format, and follows the :ref:`password-hash-api`.
@@ -236,11 +235,11 @@ class ldap_plaintext(plaintext):
hash = uh.to_unicode_for_identify(hash)
return bool(hash) and cls._2307_pat.match(hash) is None
-#=========================================================
+#=============================================================================
# {CRYPT} wrappers
# the following are wrappers around the base crypt algorithms,
# which add the ldap required {CRYPT} prefix
-#=========================================================
+#=============================================================================
ldap_crypt_schemes = [ 'ldap_' + name for name in unix_crypt_schemes ]
def _init_ldap_crypt_handlers():
@@ -266,6 +265,6 @@ _init_ldap_crypt_handlers()
## ]
## return _lcn_host
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/md5_crypt.py b/passlib/handlers/md5_crypt.py
index ec8c773..ee49236 100644
--- a/passlib/handlers/md5_crypt.py
+++ b/passlib/handlers/md5_crypt.py
@@ -1,27 +1,26 @@
"""passlib.handlers.md5_crypt - md5-crypt algorithm"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from hashlib import md5
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import classproperty, h64, safe_crypt, test_crypt, repeat_string
from passlib.utils.compat import b, bytes, irange, unicode, u
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"md5_crypt",
"apr_md5_crypt",
]
-#=========================================================
-#pure-python backend
-#=========================================================
+#=============================================================================
+# pure-python backend
+#=============================================================================
_BNULL = b("\x00")
_MD5_MAGIC = b("$1$")
_APR_MAGIC = b("$apr1$")
@@ -63,11 +62,11 @@ def _raw_md5_crypt(pwd, salt, use_apr=False):
# would love to find webpage explaining why just using a portable
# implementation of $1$ wasn't sufficient. *nothing* else was changed.
- #=====================================================================
+ #===================================================================
# init & validate inputs
- #=====================================================================
+ #===================================================================
- #validate secret
+ # validate secret
# XXX: not sure what official unicode policy is, using this as default
if isinstance(pwd, unicode):
pwd = pwd.encode("utf-8")
@@ -76,7 +75,7 @@ def _raw_md5_crypt(pwd, salt, use_apr=False):
raise uh.exc.NullPasswordError(md5_crypt)
pwd_len = len(pwd)
- #validate salt - should have been taken care of by caller
+ # validate salt - should have been taken care of by caller
assert isinstance(salt, unicode), "salt not unicode"
salt = salt.encode("ascii")
assert len(salt) < 9, "salt too large"
@@ -90,14 +89,14 @@ def _raw_md5_crypt(pwd, salt, use_apr=False):
else:
magic = _MD5_MAGIC
- #=====================================================================
+ #===================================================================
# digest B - used as subinput to digest A
- #=====================================================================
+ #===================================================================
db = md5(pwd + salt + pwd).digest()
- #=====================================================================
+ #===================================================================
# digest A - used to initialize first round of digest C
- #=====================================================================
+ #===================================================================
# start out with pwd + magic + salt
a_ctx = md5(pwd + magic + salt)
a_ctx_update = a_ctx.update
@@ -119,10 +118,10 @@ def _raw_md5_crypt(pwd, salt, use_apr=False):
# finish A
da = a_ctx.digest()
- #=====================================================================
+ #===================================================================
# digest C - for a 1000 rounds, combine A, S, and P
# digests in various ways; in order to burn CPU time.
- #=====================================================================
+ #===================================================================
# NOTE: the original MD5-Crypt implementation performs the C digest
# calculation using the following loop:
@@ -183,22 +182,22 @@ def _raw_md5_crypt(pwd, salt, use_apr=False):
for even, odd in data[:17]:
dc = md5(odd + md5(dc + even).digest()).digest()
- #=====================================================================
+ #===================================================================
# encode digest using appropriate transpose map
- #=====================================================================
+ #===================================================================
return h64.encode_transposed_bytes(dc, _transpose_map).decode("ascii")
-#=========================================================
+#=============================================================================
# handler
-#=========================================================
+#=============================================================================
class _MD5_Common(uh.HasSalt, uh.GenericHandler):
"common code for md5_crypt and apr_md5_crypt"
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
- #name - set in subclass
+ #===================================================================
+ # name - set in subclass
setting_kwds = ("salt", "salt_size")
- #ident - set in subclass
+ # ident - set in subclass
checksum_size = 22
checksum_chars = uh.HASH64_CHARS
@@ -206,9 +205,9 @@ class _MD5_Common(uh.HasSalt, uh.GenericHandler):
max_salt_size = 8
salt_chars = uh.HASH64_CHARS
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def from_string(cls, hash):
@@ -220,9 +219,9 @@ class _MD5_Common(uh.HasSalt, uh.GenericHandler):
# _calc_checksum() - provided by subclass
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
class md5_crypt(uh.HasManyBackends, _MD5_Common):
"""This class implements the MD5-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -254,17 +253,17 @@ class md5_crypt(uh.HasManyBackends, _MD5_Common):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "md5_crypt"
ident = u("$1$")
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
- #FIXME: can't find definitive policy on how md5-crypt handles non-ascii.
- # all backends currently coerce -> utf-8
+ #===================================================================
+ # FIXME: can't find definitive policy on how md5-crypt handles non-ascii.
+ # all backends currently coerce -> utf-8
backends = ("os_crypt", "builtin")
@@ -286,9 +285,9 @@ class md5_crypt(uh.HasManyBackends, _MD5_Common):
else:
return self._calc_checksum_builtin(secret)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class apr_md5_crypt(_MD5_Common):
"""This class implements the Apr-MD5-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -313,22 +312,22 @@ class apr_md5_crypt(_MD5_Common):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "apr_md5_crypt"
ident = u("$apr1$")
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
def _calc_checksum(self, secret):
return _raw_md5_crypt(secret, self.salt, use_apr=True)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/handlers/misc.py b/passlib/handlers/misc.py
index e4aaac8..e7f8fe1 100644
--- a/passlib/handlers/misc.py
+++ b/passlib/handlers/misc.py
@@ -1,28 +1,27 @@
"""passlib.handlers.misc - misc generic handlers
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import sys
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import to_native_str, consteq
from passlib.utils.compat import bytes, unicode, u, b, base_string_types
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"unix_disabled",
"unix_fallback",
"plaintext",
]
-#=========================================================
-#handler
-#=========================================================
+#=============================================================================
+# handler
+#=============================================================================
class unix_fallback(uh.StaticHandler):
"""This class provides the fallback behavior for unix shadow files, and follows the :ref:`password-hash-api`.
@@ -238,6 +237,6 @@ class plaintext(uh.PasswordHash):
raise uh.exc.InvalidHashError(cls)
return cls.encrypt(secret, encoding)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/mssql.py b/passlib/handlers/mssql.py
index 359d45a..1d89273 100644
--- a/passlib/handlers/mssql.py
+++ b/passlib/handlers/mssql.py
@@ -31,30 +31,29 @@ http://us.generation-nt.com/securing-passwords-hash-help-35429432.html
http://forum.md5decrypter.co.uk/topic230-mysql-and-mssql-get-password-hashes.aspx
http://www.theregister.co.uk/2002/07/08/cracking_ms_sql_server_passwords/
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify, unhexlify
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
-#pkg
+# site
+# pkg
from passlib.utils import consteq
from passlib.utils.compat import b, bytes, bascii_to_str, unicode, u
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
"mssql2000",
"mssql2005",
]
-#=========================================================
+#=============================================================================
# mssql 2000
-#=========================================================
+#=============================================================================
def _raw_mssql(secret, salt):
assert isinstance(secret, unicode)
assert isinstance(salt, bytes)
@@ -121,18 +120,18 @@ class mssql2000(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
will be issued instead. Correctable errors include
``salt`` strings that are too long.
"""
- #=========================================================
- #algorithm information
- #=========================================================
+ #===================================================================
+ # algorithm information
+ #===================================================================
name = "mssql2000"
setting_kwds = ("salt",)
checksum_size = 40
min_salt_size = max_salt_size = 4
_stub_checksum = b("\x00") * 40
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
# 0100 - 2 byte identifier
# 4 byte salt
@@ -175,9 +174,9 @@ class mssql2000(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
result = _raw_mssql(secret.upper(), self.salt)
return consteq(result, chk[20:])
-#=========================================================
-#handler
-#=========================================================
+#=============================================================================
+# handler
+#=============================================================================
class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"""This class implements the password hash used by MS-SQL 2005, and follows the :ref:`password-hash-api`.
@@ -199,9 +198,9 @@ class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
will be issued instead. Correctable errors include
``salt`` strings that are too long.
"""
- #=========================================================
- #algorithm information
- #=========================================================
+ #===================================================================
+ # algorithm information
+ #===================================================================
name = "mssql2005"
setting_kwds = ("salt",)
@@ -209,9 +208,9 @@ class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
min_salt_size = max_salt_size = 4
_stub_checksum = b("\x00") * 20
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
# 0x0100 - 2 byte identifier
# 4 byte salt
@@ -238,10 +237,10 @@ class mssql2005(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
secret = secret.decode("utf-8")
return _raw_mssql(secret, self.salt)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/mysql.py b/passlib/handlers/mysql.py
index e820744..8f57d05 100644
--- a/passlib/handlers/mysql.py
+++ b/passlib/handlers/mysql.py
@@ -19,30 +19,29 @@ MySQL 4.1.1 / NEW PASSWORD
Description taken from http://dev.mysql.com/doc/refman/6.0/en/password-hashing.html
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
-#pkg
+# site
+# pkg
from passlib.utils import to_native_str
from passlib.utils.compat import b, bascii_to_str, bytes, unicode, u, \
byte_elem_value, str_to_uascii
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
'mysql323',
'mysq41',
]
-#=========================================================
-#backend
-#=========================================================
+#=============================================================================
+# backend
+#=============================================================================
class mysql323(uh.StaticHandler):
"""This class implements the MySQL 3.2.3 password hash, and follows the :ref:`password-hash-api`.
@@ -50,16 +49,16 @@ class mysql323(uh.StaticHandler):
The :meth:`~passlib.ifc.PasswordHash.encrypt` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords.
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "mysql323"
checksum_size = 16
checksum_chars = uh.HEX_CHARS
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.lower()
@@ -85,13 +84,13 @@ class mysql323(uh.StaticHandler):
add = (add+tmp) & MASK_32
return u("%08x%08x") % (nr1 & MASK_31, nr2 & MASK_31)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
-#handler
-#=========================================================
+#=============================================================================
+# handler
+#=============================================================================
class mysql41(uh.StaticHandler):
"""This class implements the MySQL 4.1 password hash, and follows the :ref:`password-hash-api`.
@@ -99,17 +98,17 @@ class mysql41(uh.StaticHandler):
The :meth:`~passlib.ifc.PasswordHash.encrypt` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept no optional keywords.
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "mysql41"
_hash_prefix = u("*")
checksum_chars = uh.HEX_CHARS
checksum_size = 40
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.upper()
@@ -120,10 +119,10 @@ class mysql41(uh.StaticHandler):
secret = secret.encode("utf-8")
return str_to_uascii(sha1(sha1(secret).digest()).hexdigest()).upper()
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/oracle.py b/passlib/handlers/oracle.py
index ac45589..b826520 100644
--- a/passlib/handlers/oracle.py
+++ b/passlib/handlers/oracle.py
@@ -1,30 +1,29 @@
"""passlib.handlers.oracle - Oracle DB Password Hashes"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify, unhexlify
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
-#pkg
+# site
+# pkg
from passlib.utils import to_unicode, to_native_str, xor_bytes
from passlib.utils.compat import b, bytes, bascii_to_str, irange, u, \
uascii_to_str, unicode, str_to_uascii
from passlib.utils.des import des_encrypt_block
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
"oracle10g",
"oracle11g"
]
-#=========================================================
-#oracle10
-#=========================================================
+#=============================================================================
+# oracle10
+#=============================================================================
def des_cbc_encrypt(key, value, iv=b('\x00') * 8, pad=b('\x00')):
"""performs des-cbc encryption, returns only last block.
@@ -41,14 +40,14 @@ def des_cbc_encrypt(key, value, iv=b('\x00') * 8, pad=b('\x00')):
:returns: last block of DES-CBC encryption of all ``value``'s byte blocks.
"""
- value += pad * (-len(value) % 8) #null pad to multiple of 8
- hash = iv #start things off
+ value += pad * (-len(value) % 8) # null pad to multiple of 8
+ hash = iv # start things off
for offset in irange(0,len(value),8):
chunk = xor_bytes(hash, value[offset:offset+8])
hash = des_encrypt_block(key, chunk)
return hash
-#: magic string used as initial des key by oracle10
+# magic string used as initial des key by oracle10
ORACLE10_MAGIC = b("\x01\x23\x45\x67\x89\xAB\xCD\xEF")
class oracle10(uh.HasUserContext, uh.StaticHandler):
@@ -62,31 +61,32 @@ class oracle10(uh.HasUserContext, uh.StaticHandler):
:type user: str
:param user: name of oracle user account this password is associated with.
"""
- #=========================================================
+ #===================================================================
# algorithm information
- #=========================================================
+ #===================================================================
name = "oracle10"
checksum_chars = uh.HEX_CHARS
checksum_size = 16
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.upper()
def _calc_checksum(self, secret):
- #FIXME: not sure how oracle handles unicode.
- # online docs about 10g hash indicate it puts ascii chars
- # in a 2-byte encoding w/ the high byte set to null.
- # they don't say how it handles other chars, or what encoding.
+ # FIXME: not sure how oracle handles unicode.
+ # online docs about 10g hash indicate it puts ascii chars
+ # in a 2-byte encoding w/ the high byte set to null.
+ # they don't say how it handles other chars, or what encoding.
#
- # so for now, encoding secret & user to utf-16-be, since that fits,
- # and if secret/user is bytes, we assume utf-8, and decode first.
+ # so for now, encoding secret & user to utf-16-be,
+ # since that fits, and if secret/user is bytes,
+ # we assume utf-8, and decode first.
#
- # this whole mess really needs someone w/ an oracle system,
- # and some answers :)
+ # this whole mess really needs someone w/ an oracle system,
+ # and some answers :)
if isinstance(secret, bytes):
secret = secret.decode("utf-8")
user = to_unicode(self.user, "utf-8", param="user")
@@ -95,13 +95,13 @@ class oracle10(uh.HasUserContext, uh.StaticHandler):
hash = des_cbc_encrypt(hash, input)
return hexlify(hash).decode("ascii").upper()
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#oracle11
-#=========================================================
+#=============================================================================
+# oracle11
+#=============================================================================
class oracle11(uh.HasSalt, uh.GenericHandler):
"""This class implements the Oracle11g password hash, and follows the :ref:`password-hash-api`.
@@ -125,9 +125,9 @@ class oracle11(uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "oracle11"
setting_kwds = ("salt",)
@@ -141,9 +141,9 @@ class oracle11(uh.HasSalt, uh.GenericHandler):
salt_chars = uh.UPPER_HEX_CHARS
- #=========================================================
- #methods
- #=========================================================
+ #===================================================================
+ # methods
+ #===================================================================
_hash_regex = re.compile(u("^S:(?P<chk>[0-9a-f]{40})(?P<salt>[0-9a-f]{20})$"), re.I)
@classmethod
@@ -166,10 +166,10 @@ class oracle11(uh.HasSalt, uh.GenericHandler):
chk = sha1(secret + unhexlify(self.salt.encode("ascii"))).hexdigest()
return str_to_uascii(chk).upper()
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/pbkdf2.py b/passlib/handlers/pbkdf2.py
index 6d90675..931521b 100644
--- a/passlib/handlers/pbkdf2.py
+++ b/passlib/handlers/pbkdf2.py
@@ -1,21 +1,20 @@
"""passlib.handlers.pbkdf - PBKDF2 based hashes"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify, unhexlify
from base64 import b64encode, b64decode
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import ab64_decode, ab64_encode, to_unicode
from passlib.utils.compat import b, bytes, str_to_bascii, u, uascii_to_str, unicode
from passlib.utils.pbkdf2 import pbkdf2
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"pbkdf2_sha1",
"pbkdf2_sha256",
@@ -25,14 +24,14 @@ __all__ = [
"grub_pbkdf2_sha512",
]
-#=========================================================
+#=============================================================================
#
-#=========================================================
+#=============================================================================
class Pbkdf2DigestHandler(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"base class for various pbkdf2_{digest} algorithms"
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
setting_kwds = ("salt", "salt_size", "rounds")
@@ -50,18 +49,18 @@ class Pbkdf2DigestHandler(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gen
rounds_cost = "linear"
#--this class--
- _prf = None #subclass specified prf identifier
+ _prf = None # subclass specified prf identifier
- #NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check.
- # the underlying pbkdf2 specifies no bounds for either.
+ # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check.
+ # the underlying pbkdf2 specifies no bounds for either.
- #NOTE: defaults chosen to be at least as large as pbkdf2 rfc recommends...
- # >8 bytes of entropy in salt, >1000 rounds
- # increased due to time since rfc established
+ # NOTE: defaults chosen to be at least as large as pbkdf2 rfc recommends...
+ # >8 bytes of entropy in salt, >1000 rounds
+ # increased due to time since rfc established
- #=========================================================
- #methods
- #=========================================================
+ #===================================================================
+ # methods
+ #===================================================================
@classmethod
def from_string(cls, hash):
@@ -133,9 +132,9 @@ def create_pbkdf2_hash(hash_name, digest_size, rounds=12000, ident=None, module=
""" % dict(prf=prf.upper(), dsc=base.default_salt_size, dr=rounds)
))
-#---------------------------------------------------------
-#derived handlers
-#---------------------------------------------------------
+#------------------------------------------------------------------------
+# derived handlers
+#------------------------------------------------------------------------
pbkdf2_sha1 = create_pbkdf2_hash("sha1", 20, 60000, ident=u("$pbkdf2$"))
pbkdf2_sha256 = create_pbkdf2_hash("sha256", 32)
pbkdf2_sha512 = create_pbkdf2_hash("sha512", 64)
@@ -144,11 +143,11 @@ ldap_pbkdf2_sha1 = uh.PrefixWrapper("ldap_pbkdf2_sha1", pbkdf2_sha1, "{PBKDF2}",
ldap_pbkdf2_sha256 = uh.PrefixWrapper("ldap_pbkdf2_sha256", pbkdf2_sha256, "{PBKDF2-SHA256}", "$pbkdf2-sha256$", ident=True)
ldap_pbkdf2_sha512 = uh.PrefixWrapper("ldap_pbkdf2_sha512", pbkdf2_sha512, "{PBKDF2-SHA512}", "$pbkdf2-sha512$", ident=True)
-#=========================================================
-#cryptacular's pbkdf2 hash
-#=========================================================
+#=============================================================================
+# cryptacular's pbkdf2 hash
+#=============================================================================
-#: bytes used by cta hash for base64 values 63 & 64
+# bytes used by cta hash for base64 values 63 & 64
CTA_ALTCHARS = b("-_")
class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
@@ -185,16 +184,17 @@ class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Generic
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "cta_pbkdf2_sha1"
setting_kwds = ("salt", "salt_size", "rounds")
ident = u("$p5k2$")
- #NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check.
- # underlying algorithm (and reference implementation) allow effectively unbounded values for both of these.
+ # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a
+ # sanity check. underlying algorithm (and reference implementation)
+ # allows effectively unbounded values for both of these parameters.
#--HasSalt--
default_salt_size = 16
@@ -207,16 +207,16 @@ class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Generic
max_rounds = 0xffffffff # setting at 32-bit limit for now
rounds_cost = "linear"
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
- #hash $p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0=
- #ident $p5k2$
- #rounds 1000
- #salt ZxK4ZBJCfQg=
- #chk jJZVscWtO--p1-xIZl6jhO2LKR0=
- #NOTE: rounds in hex
+ # hash $p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0=
+ # ident $p5k2$
+ # rounds 1000
+ # salt ZxK4ZBJCfQg=
+ # chk jJZVscWtO--p1-xIZl6jhO2LKR0=
+ # NOTE: rounds in hex
@classmethod
def from_string(cls, hash):
@@ -235,21 +235,21 @@ class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Generic
chk = None
return uh.render_mc3(self.ident, self.rounds, salt, chk, rounds_base=16)
- #=========================================================
- #backend
- #=========================================================
+ #===================================================================
+ # backend
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
return pbkdf2(secret, self.salt, self.rounds, 20, "hmac-sha1")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#dlitz's pbkdf2 hash
-#=========================================================
+#=============================================================================
+# dlitz's pbkdf2 hash
+#=============================================================================
class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
"""This class implements Dwayne Litzenberger's PBKDF2-based crypt algorithm, and follows the :ref:`password-hash-api`.
@@ -284,16 +284,17 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "dlitz_pbkdf2_sha1"
setting_kwds = ("salt", "salt_size", "rounds")
ident = u("$p5k2$")
- #NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check.
- # underlying algorithm (and reference implementation) allow effectively unbounded values for both of these.
+ # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a
+ # sanity check. underlying algorithm (and reference implementation)
+ # allows effectively unbounded values for both of these parameters.
#--HasSalt--
default_salt_size = 16
@@ -307,16 +308,16 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
max_rounds = 0xffffffff # setting at 32-bit limit for now
rounds_cost = "linear"
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
- #hash $p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g
- #ident $p5k2$
- #rounds c
- #salt u9HvcT4d
- #chk Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g
- #rounds in lowercase hex, no zero padding
+ # hash $p5k2$c$u9HvcT4d$Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g
+ # ident $p5k2$
+ # rounds c
+ # salt u9HvcT4d
+ # chk Sd1gwSVCLZYAuqZ25piRnbBEoAesaa/g
+ # rounds in lowercase hex, no zero padding
@classmethod
def from_string(cls, hash):
@@ -332,9 +333,9 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
checksum=self.checksum if withchk else None,
rounds_base=16)
- #=========================================================
- #backend
- #=========================================================
+ #===================================================================
+ # backend
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
@@ -342,13 +343,13 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
result = pbkdf2(secret, salt, self.rounds, 24, "hmac-sha1")
return ab64_encode(result).decode("ascii")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#crowd
-#=========================================================
+#=============================================================================
+# crowd
+#=============================================================================
class atlassian_pbkdf2_sha1(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"""This class implements the PBKDF2 hash used by Atlassian.
@@ -399,15 +400,15 @@ class atlassian_pbkdf2_sha1(uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler)
return uascii_to_str(hash)
def _calc_checksum(self, secret):
- #TODO: find out what crowd's policy is re: unicode
+ # TODO: find out what crowd's policy is re: unicode
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
- #crowd seems to use a fixed number of rounds.
+ # crowd seems to use a fixed number of rounds.
return pbkdf2(secret, self.salt, 10000, 32, "hmac-sha1")
-#=========================================================
-#grub
-#=========================================================
+#=============================================================================
+# grub
+#=============================================================================
class grub_pbkdf2_sha512(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"""This class implements Grub's pbkdf2-hmac-sha512 hash, and follows the :ref:`password-hash-api`.
@@ -446,9 +447,9 @@ class grub_pbkdf2_sha512(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gene
ident = u("grub.pbkdf2.sha512.")
- #NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide sanity check.
- # the underlying pbkdf2 specifies no bounds for either,
- # and it's not clear what grub specifies.
+ # NOTE: max_salt_size and max_rounds are arbitrarily chosen to provide a
+ # sanity check. the underlying pbkdf2 specifies no bounds for either,
+ # and it's not clear what grub specifies.
default_salt_size = 64
min_salt_size = 0
@@ -477,11 +478,11 @@ class grub_pbkdf2_sha512(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gene
return uh.render_mc3(self.ident, self.rounds, salt, chk, sep=u("."))
def _calc_checksum(self, secret):
- #TODO: find out what grub's policy is re: unicode
+ # TODO: find out what grub's policy is re: unicode
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
return pbkdf2(secret, self.salt, self.rounds, 64, "hmac-sha512")
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/phpass.py b/passlib/handlers/phpass.py
index 0cafea1..bf09181 100644
--- a/passlib/handlers/phpass.py
+++ b/passlib/handlers/phpass.py
@@ -5,28 +5,27 @@ algorithm described - http://www.openwall.com/articles/PHP-Users-Passwords
phpass context - blowfish, bsdi_crypt, phpass
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from hashlib import md5
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import h64
from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"phpass",
]
-#=========================================================
-#phpass
-#=========================================================
+#=============================================================================
+# phpass
+#=============================================================================
class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
"""This class implements the PHPass Portable Hash, and follows the :ref:`password-hash-api`.
@@ -63,9 +62,9 @@ class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "phpass"
setting_kwds = ("salt", "rounds", "ident")
@@ -86,9 +85,9 @@ class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
ident_values = [u("$P$"), u("$H$")]
ident_aliases = {u("P"):u("$P$"), u("H"):u("$H$")}
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
#$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0
# $P$
@@ -114,11 +113,11 @@ class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
self.checksum or u(''))
return uascii_to_str(hash)
- #=========================================================
- #backend
- #=========================================================
+ #===================================================================
+ # backend
+ #===================================================================
def _calc_checksum(self, secret):
- #FIXME: can't find definitive policy on how phpass handles non-ascii.
+ # FIXME: can't find definitive policy on how phpass handles non-ascii.
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
real_rounds = 1<<self.rounds
@@ -129,10 +128,10 @@ class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
r += 1
return h64.encode_bytes(result).decode("ascii")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/postgres.py b/passlib/handlers/postgres.py
index 1324d83..b8683dd 100644
--- a/passlib/handlers/postgres.py
+++ b/passlib/handlers/postgres.py
@@ -1,26 +1,25 @@
"""passlib.handlers.postgres_md5 - MD5-based algorithm used by Postgres for pg_shadow table"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from hashlib import md5
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
-#pkg
+# site
+# pkg
from passlib.utils import to_bytes
from passlib.utils.compat import b, bytes, str_to_uascii, unicode, u
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
"postgres_md5",
]
-#=========================================================
-#handler
-#=========================================================
+#=============================================================================
+# handler
+#=============================================================================
class postgres_md5(uh.HasUserContext, uh.StaticHandler):
"""This class implements the Postgres MD5 Password hash, and follows the :ref:`password-hash-api`.
@@ -32,27 +31,27 @@ class postgres_md5(uh.HasUserContext, uh.StaticHandler):
:type user: str
:param user: name of postgres user account this password is associated with.
"""
- #=========================================================
+ #===================================================================
# algorithm information
- #=========================================================
+ #===================================================================
name = "postgres_md5"
_hash_prefix = u("md5")
checksum_chars = uh.HEX_CHARS
checksum_size = 32
- #=========================================================
+ #===================================================================
# primary interface
- #=========================================================
+ #===================================================================
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
user = to_bytes(self.user, "utf-8", param="user")
return str_to_uascii(md5(secret + user).hexdigest())
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/roundup.py b/passlib/handlers/roundup.py
index ac9a189..c7f99c1 100644
--- a/passlib/handlers/roundup.py
+++ b/passlib/handlers/roundup.py
@@ -1,30 +1,29 @@
"""passlib.handlers.roundup - Roundup issue tracker hashes"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import logging; log = logging.getLogger(__name__)
-#site
-#libs
+# site
+# pkg
import passlib.utils.handlers as uh
from passlib.utils.compat import u
-#pkg
-#local
+# local
__all__ = [
"roundup_plaintext",
"ldap_hex_md5",
"ldap_hex_sha1",
]
-#=========================================================
+#=============================================================================
#
-#=========================================================
+#=============================================================================
roundup_plaintext = uh.PrefixWrapper("roundup_plaintext", "plaintext",
prefix=u("{plaintext}"), lazy=True)
-#NOTE: these are here because they're currently only known to be used by roundup
+# NOTE: these are here because they're currently only known to be used by roundup
ldap_hex_md5 = uh.PrefixWrapper("ldap_hex_md5", "hex_md5", u("{MD5}"), lazy=True)
ldap_hex_sha1 = uh.PrefixWrapper("ldap_hex_sha1", "hex_sha1", u("{SHA}"), lazy=True)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/scram.py b/passlib/handlers/scram.py
index 2af3980..0dbc823 100644
--- a/passlib/handlers/scram.py
+++ b/passlib/handlers/scram.py
@@ -1,16 +1,16 @@
"""passlib.handlers.scram - hash for SCRAM credential storage"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify, unhexlify
from base64 import b64encode, b64decode
import hashlib
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.exc import PasslibHashWarning
from passlib.utils import ab64_decode, ab64_encode, consteq, saslprep, \
to_native_str, xor_bytes, splitcomma
@@ -18,15 +18,14 @@ from passlib.utils.compat import b, bytes, bascii_to_str, iteritems, \
PY3, u, unicode
from passlib.utils.pbkdf2 import pbkdf2, get_prf, norm_hash_name
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"scram",
]
-#=========================================================
+#=============================================================================
# scram credentials hash
-#=========================================================
+#=============================================================================
class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"""This class provides a format for storing SCRAM passwords, and follows
the :ref:`password-hash-api`.
@@ -81,9 +80,9 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
.. automethod:: extract_digest_algs
.. automethod:: derive_digest
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
# NOTE: unlike most GenericHandler classes, the 'checksum' attr of
# ScramHandler is actually a map from digest_name -> digest, so
@@ -116,20 +115,20 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
# list of algs verify prefers to use, in order.
_verify_algs = ["sha-256", "sha-512", "sha-224", "sha-384", "sha-1"]
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
# 'checksum' is different from most GenericHandler subclasses,
# in that it contains a dict mapping from alg -> digest,
# or None if no checksum present.
- #: list of algorithms to create/compare digests for.
+ # list of algorithms to create/compare digests for.
algs = None
- #=========================================================
+ #===================================================================
# scram frontend helpers
- #=========================================================
+ #===================================================================
@classmethod
def extract_digest_info(cls, hash, alg):
"""return (salt, rounds, digest) for specific hash algorithm.
@@ -228,9 +227,9 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
alg = norm_hash_name(alg, "hashlib")
return pbkdf2(password, salt, rounds, None, "hmac-" + alg)
- #=========================================================
+ #===================================================================
# serialization
- #=========================================================
+ #===================================================================
@classmethod
def from_string(cls, hash):
@@ -244,7 +243,7 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
# decode rounds
rounds = int(rounds_str)
- if rounds_str != str(rounds): #forbid zero padding, etc.
+ if rounds_str != str(rounds): # forbid zero padding, etc.
raise uh.exc.MalformedHashError(cls)
# decode salt
@@ -292,9 +291,9 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
chk_str = ",".join(self.algs)
return '$scram$%d$%s$%s' % (self.rounds, salt, chk_str)
- #=========================================================
+ #===================================================================
# init
- #=========================================================
+ #===================================================================
def __init__(self, algs=None, **kwds):
super(scram, self).__init__(**kwds)
self.algs = self._norm_algs(algs)
@@ -343,9 +342,9 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
raise ValueError("sha-1 must be in algorithm list of scram hash")
return algs
- #=========================================================
+ #===================================================================
# digest methods
- #=========================================================
+ #===================================================================
@classmethod
def _bind_needs_update(cls, **settings):
@@ -414,164 +413,164 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
# or something went wrong inside _norm_algs()
raise AssertionError("sha-1 digest not found!")
- #=========================================================
+ #===================================================================
#
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# code used for testing scram against protocol examples during development.
-#=========================================================
-#def _test_reference_scram():
-# "quick hack testing scram reference vectors"
-# # NOTE: "n,," is GS2 header - see https://tools.ietf.org/html/rfc5801
-# from passlib.utils.compat import print_
-#
-# engine = _scram_engine(
-# alg="sha-1",
-# salt='QSXCR+Q6sek8bf92'.decode("base64"),
-# rounds=4096,
-# password=u("pencil"),
-# )
-# print_(engine.digest.encode("base64").rstrip())
-#
-# msg = engine.format_auth_msg(
-# username="user",
-# client_nonce = "fyko+d2lbbFgONRv9qkxdawL",
-# server_nonce = "3rfcNHYJY1ZVvWVs7j",
-# header='c=biws',
-# )
-#
-# cp = engine.get_encoded_client_proof(msg)
-# assert cp == "v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=", cp
-#
-# ss = engine.get_encoded_server_sig(msg)
-# assert ss == "rmF9pqV8S7suAoZWja4dJRkFsKQ=", ss
-#
-#class _scram_engine(object):
-# """helper class for verifying scram hash behavior
-# against SCRAM protocol examples. not officially part of Passlib.
-#
-# takes in alg, salt, rounds, and a digest or password.
-#
-# can calculate the various keys & messages of the scram protocol.
-#
-# """
-# #=========================================================
-# # init
-# #=========================================================
-#
-# @classmethod
-# def from_string(cls, hash, alg):
-# "create record from scram hash, for given alg"
-# return cls(alg, *scram.extract_digest_info(hash, alg))
-#
-# def __init__(self, alg, salt, rounds, digest=None, password=None):
-# self.alg = norm_hash_name(alg)
-# self.salt = salt
-# self.rounds = rounds
-# self.password = password
-# if password:
-# data = scram.derive_digest(password, salt, rounds, alg)
-# if digest and data != digest:
-# raise ValueError("password doesn't match digest")
-# else:
-# digest = data
-# elif not digest:
-# raise TypeError("must provide password or digest")
-# self.digest = digest
-#
-# #=========================================================
-# # frontend methods
-# #=========================================================
-# def get_hash(self, data):
-# "return hash of raw data"
-# return hashlib.new(iana_to_hashlib(self.alg), data).digest()
-#
-# def get_client_proof(self, msg):
-# "return client proof of specified auth msg text"
-# return xor_bytes(self.client_key, self.get_client_sig(msg))
-#
-# def get_encoded_client_proof(self, msg):
-# return self.get_client_proof(msg).encode("base64").rstrip()
-#
-# def get_client_sig(self, msg):
-# "return client signature of specified auth msg text"
-# return self.get_hmac(self.stored_key, msg)
-#
-# def get_server_sig(self, msg):
-# "return server signature of specified auth msg text"
-# return self.get_hmac(self.server_key, msg)
-#
-# def get_encoded_server_sig(self, msg):
-# return self.get_server_sig(msg).encode("base64").rstrip()
-#
-# def format_server_response(self, client_nonce, server_nonce):
-# return 'r={client_nonce}{server_nonce},s={salt},i={rounds}'.format(
-# client_nonce=client_nonce,
-# server_nonce=server_nonce,
-# rounds=self.rounds,
-# salt=self.encoded_salt,
-# )
-#
-# def format_auth_msg(self, username, client_nonce, server_nonce,
-# header='c=biws'):
-# return (
-# 'n={username},r={client_nonce}'
-# ','
-# 'r={client_nonce}{server_nonce},s={salt},i={rounds}'
-# ','
-# '{header},r={client_nonce}{server_nonce}'
-# ).format(
-# username=username,
-# client_nonce=client_nonce,
-# server_nonce=server_nonce,
-# salt=self.encoded_salt,
-# rounds=self.rounds,
-# header=header,
-# )
-#
-# #=========================================================
-# # helpers to calculate & cache constant data
-# #=========================================================
-# def _calc_get_hmac(self):
-# return get_prf("hmac-" + iana_to_hashlib(self.alg))[0]
-#
-# def _calc_client_key(self):
-# return self.get_hmac(self.digest, b("Client Key"))
-#
-# def _calc_stored_key(self):
-# return self.get_hash(self.client_key)
-#
-# def _calc_server_key(self):
-# return self.get_hmac(self.digest, b("Server Key"))
-#
-# def _calc_encoded_salt(self):
-# return self.salt.encode("base64").rstrip()
-#
-# #=========================================================
-# # hacks for calculated attributes
-# #=========================================================
-#
-# def __getattr__(self, attr):
-# if not attr.startswith("_"):
-# f = getattr(self, "_calc_" + attr, None)
-# if f:
-# value = f()
-# setattr(self, attr, value)
-# return value
-# raise AttributeError("attribute not found")
-#
-# def __dir__(self):
-# cdir = dir(self.__class__)
-# attrs = set(cdir)
-# attrs.update(self.__dict__)
-# attrs.update(attr[6:] for attr in cdir
-# if attr.startswith("_calc_"))
-# return sorted(attrs)
-# #=========================================================
-# # eoc
-# #=========================================================
-
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+##def _test_reference_scram():
+## "quick hack testing scram reference vectors"
+## # NOTE: "n,," is GS2 header - see https://tools.ietf.org/html/rfc5801
+## from passlib.utils.compat import print_
+##
+## engine = _scram_engine(
+## alg="sha-1",
+## salt='QSXCR+Q6sek8bf92'.decode("base64"),
+## rounds=4096,
+## password=u("pencil"),
+## )
+## print_(engine.digest.encode("base64").rstrip())
+##
+## msg = engine.format_auth_msg(
+## username="user",
+## client_nonce = "fyko+d2lbbFgONRv9qkxdawL",
+## server_nonce = "3rfcNHYJY1ZVvWVs7j",
+## header='c=biws',
+## )
+##
+## cp = engine.get_encoded_client_proof(msg)
+## assert cp == "v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=", cp
+##
+## ss = engine.get_encoded_server_sig(msg)
+## assert ss == "rmF9pqV8S7suAoZWja4dJRkFsKQ=", ss
+##
+##class _scram_engine(object):
+## """helper class for verifying scram hash behavior
+## against SCRAM protocol examples. not officially part of Passlib.
+##
+## takes in alg, salt, rounds, and a digest or password.
+##
+## can calculate the various keys & messages of the scram protocol.
+##
+## """
+## #=========================================================
+## # init
+## #=========================================================
+##
+## @classmethod
+## def from_string(cls, hash, alg):
+## "create record from scram hash, for given alg"
+## return cls(alg, *scram.extract_digest_info(hash, alg))
+##
+## def __init__(self, alg, salt, rounds, digest=None, password=None):
+## self.alg = norm_hash_name(alg)
+## self.salt = salt
+## self.rounds = rounds
+## self.password = password
+## if password:
+## data = scram.derive_digest(password, salt, rounds, alg)
+## if digest and data != digest:
+## raise ValueError("password doesn't match digest")
+## else:
+## digest = data
+## elif not digest:
+## raise TypeError("must provide password or digest")
+## self.digest = digest
+##
+## #=========================================================
+## # frontend methods
+## #=========================================================
+## def get_hash(self, data):
+## "return hash of raw data"
+## return hashlib.new(iana_to_hashlib(self.alg), data).digest()
+##
+## def get_client_proof(self, msg):
+## "return client proof of specified auth msg text"
+## return xor_bytes(self.client_key, self.get_client_sig(msg))
+##
+## def get_encoded_client_proof(self, msg):
+## return self.get_client_proof(msg).encode("base64").rstrip()
+##
+## def get_client_sig(self, msg):
+## "return client signature of specified auth msg text"
+## return self.get_hmac(self.stored_key, msg)
+##
+## def get_server_sig(self, msg):
+## "return server signature of specified auth msg text"
+## return self.get_hmac(self.server_key, msg)
+##
+## def get_encoded_server_sig(self, msg):
+## return self.get_server_sig(msg).encode("base64").rstrip()
+##
+## def format_server_response(self, client_nonce, server_nonce):
+## return 'r={client_nonce}{server_nonce},s={salt},i={rounds}'.format(
+## client_nonce=client_nonce,
+## server_nonce=server_nonce,
+## rounds=self.rounds,
+## salt=self.encoded_salt,
+## )
+##
+## def format_auth_msg(self, username, client_nonce, server_nonce,
+## header='c=biws'):
+## return (
+## 'n={username},r={client_nonce}'
+## ','
+## 'r={client_nonce}{server_nonce},s={salt},i={rounds}'
+## ','
+## '{header},r={client_nonce}{server_nonce}'
+## ).format(
+## username=username,
+## client_nonce=client_nonce,
+## server_nonce=server_nonce,
+## salt=self.encoded_salt,
+## rounds=self.rounds,
+## header=header,
+## )
+##
+## #=========================================================
+## # helpers to calculate & cache constant data
+## #=========================================================
+## def _calc_get_hmac(self):
+## return get_prf("hmac-" + iana_to_hashlib(self.alg))[0]
+##
+## def _calc_client_key(self):
+## return self.get_hmac(self.digest, b("Client Key"))
+##
+## def _calc_stored_key(self):
+## return self.get_hash(self.client_key)
+##
+## def _calc_server_key(self):
+## return self.get_hmac(self.digest, b("Server Key"))
+##
+## def _calc_encoded_salt(self):
+## return self.salt.encode("base64").rstrip()
+##
+## #=========================================================
+## # hacks for calculated attributes
+## #=========================================================
+##
+## def __getattr__(self, attr):
+## if not attr.startswith("_"):
+## f = getattr(self, "_calc_" + attr, None)
+## if f:
+## value = f()
+## setattr(self, attr, value)
+## return value
+## raise AttributeError("attribute not found")
+##
+## def __dir__(self):
+## cdir = dir(self.__class__)
+## attrs = set(cdir)
+## attrs.update(self.__dict__)
+## attrs.update(attr[6:] for attr in cdir
+## if attr.startswith("_calc_"))
+## return sorted(attrs)
+## #=========================================================
+## # eoc
+## #=========================================================
+
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/sha1_crypt.py b/passlib/handlers/sha1_crypt.py
index 5098a72..4dfaf5a 100644
--- a/passlib/handlers/sha1_crypt.py
+++ b/passlib/handlers/sha1_crypt.py
@@ -1,29 +1,28 @@
"""passlib.handlers.sha1_crypt
"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
-#core
+# core
from hmac import new as hmac
from hashlib import sha1
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import classproperty, h64, safe_crypt, test_crypt
from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode
from passlib.utils.pbkdf2 import get_prf
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
]
-#=========================================================
-#sha1-crypt
-#=========================================================
+#=============================================================================
+# sha1-crypt
+#=============================================================================
_hmac_sha1 = get_prf("hmac-sha1")[0]
_BNULL = b('\x00')
@@ -61,9 +60,9 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
#--GenericHandler--
name = "sha1_crypt"
setting_kwds = ("salt", "salt_size", "rounds")
@@ -78,14 +77,14 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
salt_chars = uh.HASH64_CHARS
#--HasRounds--
- default_rounds = 40000 #current passlib default
- min_rounds = 1 #really, this should be higher.
+ default_rounds = 40000 # current passlib default
+ min_rounds = 1 # really, this should be higher.
max_rounds = 4294967295 # 32-bit integer limit
rounds_cost = "linear"
- #=========================================================
- #formatting
- #=========================================================
+ #===================================================================
+ # formatting
+ #===================================================================
@classmethod
def from_string(cls, hash):
@@ -96,9 +95,9 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
chk = None if config else self.checksum
return uh.render_mc3(self.ident, self.rounds, self.salt, chk)
- #=========================================================
- #backend
- #=========================================================
+ #===================================================================
+ # backend
+ #===================================================================
backends = ("os_crypt", "builtin")
_has_backend_builtin = True
@@ -142,10 +141,10 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
else:
return self._calc_checksum_builtin(secret)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/sha2_crypt.py b/passlib/handlers/sha2_crypt.py
index 065102a..dbd848f 100644
--- a/passlib/handlers/sha2_crypt.py
+++ b/passlib/handlers/sha2_crypt.py
@@ -1,29 +1,28 @@
"""passlib.handlers.sha2_crypt - SHA256-Crypt / SHA512-Crypt"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import hashlib
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import classproperty, h64, safe_crypt, test_crypt, \
repeat_string, to_unicode
from passlib.utils.compat import b, bytes, byte_elem_value, irange, u, \
uascii_to_str, unicode
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"sha512_crypt",
"sha256_crypt",
]
-#==============================================================
+#=============================================================================
# pure-python backend, used by both sha256_crypt & sha512_crypt
# when crypt.crypt() backend is not available.
-#==============================================================
+#=============================================================================
_BNULL = b('\x00')
# pre-calculated offsets used to speed up C digest stage (see notes below).
@@ -69,9 +68,9 @@ def _raw_sha2_crypt(pwd, salt, rounds, use_512=False):
:returns:
encoded checksum chars
"""
- #=====================================================================
+ #===================================================================
# init & validate inputs
- #=====================================================================
+ #===================================================================
# validate secret
if isinstance(pwd, unicode):
@@ -107,14 +106,14 @@ def _raw_sha2_crypt(pwd, salt, rounds, use_512=False):
hash_len = 32
transpose_map = _256_transpose_map
- #=====================================================================
+ #===================================================================
# digest B - used as subinput to digest A
- #=====================================================================
+ #===================================================================
db = hash_const(pwd + salt + pwd).digest()
- #=====================================================================
+ #===================================================================
# digest A - used to initialize first round of digest C
- #=====================================================================
+ #===================================================================
# start out with pwd + salt
a_ctx = hash_const(pwd + salt)
a_ctx_update = a_ctx.update
@@ -131,10 +130,10 @@ def _raw_sha2_crypt(pwd, salt, rounds, use_512=False):
# finish A
da = a_ctx.digest()
- #=====================================================================
+ #===================================================================
# digest P from password - used instead of password itself
# when calculating digest C.
- #=====================================================================
+ #===================================================================
if pwd_len < 64:
# method this is faster under python, but uses O(pwd_len**2) memory
# so we don't use it for larger passwords, to avoid a potential DOS.
@@ -149,16 +148,16 @@ def _raw_sha2_crypt(pwd, salt, rounds, use_512=False):
dp = repeat_string(tmp_ctx.digest(), pwd_len)
assert len(dp) == pwd_len
- #=====================================================================
+ #===================================================================
# digest S - used instead of salt itself when calculating digest C
- #=====================================================================
+ #===================================================================
ds = hash_const(salt * (16 + byte_elem_value(da[0]))).digest()[:salt_len]
assert len(ds) == salt_len, "salt_len somehow > hash_len!"
- #=====================================================================
+ #===================================================================
# digest C - for a variable number of rounds, combine A, S, and P
# digests in various ways; in order to burn CPU time.
- #=====================================================================
+ #===================================================================
# NOTE: the original SHA256/512-Crypt specification performs the C digest
# calculation using the following loop:
@@ -227,14 +226,14 @@ def _raw_sha2_crypt(pwd, salt, rounds, use_512=False):
if tail & 1:
dc = hash_const(dc + data[pairs][0]).digest()
- #=====================================================================
+ #===================================================================
# encode digest using appropriate transpose map
- #=====================================================================
+ #===================================================================
return h64.encode_transposed_bytes(dc, transpose_map).decode("ascii")
-#=========================================================
+#=============================================================================
# handlers
-#=========================================================
+#=============================================================================
_UROUNDS = u("rounds=")
_UDOLLAR = u("$")
_UZERO = u("0")
@@ -242,9 +241,9 @@ _UZERO = u("0")
class _SHA2_Common(uh.HasManyBackends, uh.HasRounds, uh.HasSalt,
uh.GenericHandler):
"class containing common code shared by sha256_crypt & sha512_crypt"
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
# name - set by subclass
setting_kwds = ("salt", "rounds", "implicit_rounds", "salt_size")
# ident - set by subclass
@@ -262,9 +261,9 @@ class _SHA2_Common(uh.HasManyBackends, uh.HasRounds, uh.HasSalt,
_cdb_use_512 = False # flag for _calc_digest_builtin()
_rounds_prefix = None # ident + _UROUNDS
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
implicit_rounds = False
def __init__(self, implicit_rounds=None, **kwds):
@@ -331,9 +330,9 @@ class _SHA2_Common(uh.HasManyBackends, uh.HasRounds, uh.HasSalt,
self.salt, self.checksum or u(''))
return uascii_to_str(hash)
- #=========================================================
+ #===================================================================
# backends
- #=========================================================
+ #===================================================================
backends = ("os_crypt", "builtin")
_has_backend_builtin = True
@@ -355,9 +354,9 @@ class _SHA2_Common(uh.HasManyBackends, uh.HasRounds, uh.HasSalt,
else:
return self._calc_checksum_builtin(secret)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class sha256_crypt(_SHA2_Common):
"""This class implements the SHA256-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -396,29 +395,29 @@ class sha256_crypt(_SHA2_Common):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "sha256_crypt"
ident = u("$5$")
checksum_size = 43
default_rounds = 80000 # current passlib default
- #=========================================================
+ #===================================================================
# backends
- #=========================================================
+ #===================================================================
@classproperty
def _has_backend_os_crypt(cls):
return test_crypt("test", "$5$rounds=1000$test$QmQADEXMG8POI5W"
"Dsaeho0P36yK3Tcrgboabng6bkb/")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#sha 512 crypt
-#=========================================================
+#=============================================================================
+# sha 512 crypt
+#=============================================================================
class sha512_crypt(_SHA2_Common):
"""This class implements the SHA512-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -457,18 +456,18 @@ class sha512_crypt(_SHA2_Common):
.. versionadded:: 1.6
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "sha512_crypt"
ident = u("$6$")
checksum_size = 86
_cdb_use_512 = True
default_rounds = 60000 # current passlib default
- #=========================================================
+ #===================================================================
# backend
- #=========================================================
+ #===================================================================
@classproperty
def _has_backend_os_crypt(cls):
return test_crypt("test", "$6$rounds=1000$test$2M/Lx6Mtobqj"
@@ -476,10 +475,10 @@ class sha512_crypt(_SHA2_Common):
"yWeBdRDx4DU.1H3eGmse6pgsOgDisWBG"
"I5c7TZauS0")
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/handlers/sun_md5_crypt.py b/passlib/handlers/sun_md5_crypt.py
index 8296e5e..a99289c 100644
--- a/passlib/handlers/sun_md5_crypt.py
+++ b/passlib/handlers/sun_md5_crypt.py
@@ -7,30 +7,29 @@
See documentation for details.
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from hashlib import md5
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import h64, to_unicode
from passlib.utils.compat import b, bytes, byte_elem_value, irange, u, \
uascii_to_str, unicode, str_to_bascii
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"sun_md5_crypt",
]
-#=========================================================
-#backend
-#=========================================================
-#constant data used by alg - Hamlet act 3 scene 1 + null char
+#=============================================================================
+# backend
+#=============================================================================
+# constant data used by alg - Hamlet act 3 scene 1 + null char
# exact bytes as in http://www.ibiblio.org/pub/docs/books/gutenberg/etext98/2ws2610.txt
# from Project Gutenberg.
@@ -72,13 +71,13 @@ MAGIC_HAMLET = b(
"Be all my sins remember'd.\n\x00" #<- apparently null at end of C string is included (test vector won't pass otherwise)
)
-#NOTE: these sequences are pre-calculated iteration ranges used by X & Y loops w/in rounds function below
+# NOTE: these sequences are pre-calculated iteration ranges used by X & Y loops w/in rounds function below
xr = irange(7)
_XY_ROUNDS = [
- tuple((i,i,i+3) for i in xr), #xrounds 0
- tuple((i,i+1,i+4) for i in xr), #xrounds 1
- tuple((i,i+8,(i+11)&15) for i in xr), #yrounds 0
- tuple((i,(i+9)&15, (i+12)&15) for i in xr), #yrounds 1
+ tuple((i,i,i+3) for i in xr), # xrounds 0
+ tuple((i,i+1,i+4) for i in xr), # xrounds 1
+ tuple((i,i+8,(i+11)&15) for i in xr), # yrounds 0
+ tuple((i,(i+9)&15, (i+12)&15) for i in xr), # yrounds 1
]
del xr
@@ -88,37 +87,45 @@ def raw_sun_md5_crypt(secret, rounds, salt):
assert isinstance(secret, bytes)
assert isinstance(salt, bytes)
- #validate rounds
+ # validate rounds
if rounds <= 0:
rounds = 0
real_rounds = 4096 + rounds
- #NOTE: spec seems to imply max 'rounds' is 2**32-1
+ # NOTE: spec seems to imply max 'rounds' is 2**32-1
- #generate initial digest to start off round 0.
- #NOTE: algorithm 'salt' includes full config string w/ trailing "$"
+ # generate initial digest to start off round 0.
+ # NOTE: algorithm 'salt' includes full config string w/ trailing "$"
result = md5(secret + salt).digest()
assert len(result) == 16
- #NOTE: many things have been inlined to speed up the loop as much as possible,
- # so that this only barely resembles the algorithm as described in the docs.
- # * all accesses to a given bit have been inlined using the formula
- # rbitval(bit) = (rval((bit>>3) & 15) >> (bit & 7)) & 1
- # * the calculation of coinflip value R has been inlined
- # * the conditional division of coinflip value V has been inlined as a shift right of 0 or 1.
- # * the i, i+3, etc iterations are precalculated in lists.
- # * the round-based conditional division of x & y is now performed
- # by choosing an appropriate precalculated list, so only the 7 used bits
- # are actually calculated
+ # NOTE: many things in this function have been inlined (to speed up the loop
+ # as much as possible), to the point that this code barely resembles
+ # the algorithm as described in the docs. in particular:
+ #
+ # * all accesses to a given bit have been inlined using the formula
+ # rbitval(bit) = (rval((bit>>3) & 15) >> (bit & 7)) & 1
+ #
+ # * the calculation of coinflip value R has been inlined
+ #
+ # * the conditional division of coinflip value V has been inlined as
+ # a shift right of 0 or 1.
+ #
+ # * the i, i+3, etc iterations are precalculated in lists.
+ #
+ # * the round-based conditional division of x & y is now performed
+ # by choosing an appropriate precalculated list, so that it only
+ # calculates the 7 bits which will actually be used.
+ #
X_ROUNDS_0, X_ROUNDS_1, Y_ROUNDS_0, Y_ROUNDS_1 = _XY_ROUNDS
- #NOTE: % appears to be *slightly* slower than &, so we prefer & if possible
+ # NOTE: % appears to be *slightly* slower than &, so we prefer & if possible
round = 0
while round < real_rounds:
- #convert last result byte string to list of byte-ints for easy access
+ # convert last result byte string to list of byte-ints for easy access
rval = [ byte_elem_value(c) for c in result ].__getitem__
- #build up X bit by bit
+ # build up X bit by bit
x = 0
xrounds = X_ROUNDS_1 if (rval((round>>3) & 15)>>(round & 7)) & 1 else X_ROUNDS_0
for i, ia, ib in xrounds:
@@ -127,7 +134,7 @@ def raw_sun_md5_crypt(secret, rounds, salt):
v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1)
x |= ((rval((v>>3)&15)>>(v&7))&1) << i
- #build up Y bit by bit
+ # build up Y bit by bit
y = 0
yrounds = Y_ROUNDS_1 if (rval(((round+64)>>3) & 15)>>(round & 7)) & 1 else Y_ROUNDS_0
for i, ia, ib in yrounds:
@@ -136,10 +143,10 @@ def raw_sun_md5_crypt(secret, rounds, salt):
v = rval((a >> (b % 5)) & 15) >> ((b>>(a&7)) & 1)
y |= ((rval((v>>3)&15)>>(v&7))&1) << i
- #extract x'th and y'th bit, xoring them together to yeild "coin flip"
+ # extract x'th and y'th bit, xoring them together to yeild "coin flip"
coin = ((rval(x>>3) >> (x&7)) ^ (rval(y>>3) >> (y&7))) & 1
- #construct hash for this round
+ # construct hash for this round
h = md5(result)
if coin:
h.update(MAGIC_HAMLET)
@@ -148,10 +155,10 @@ def raw_sun_md5_crypt(secret, rounds, salt):
round += 1
- #encode output
+ # encode output
return h64.encode_transposed_bytes(result, _chk_offsets)
-#NOTE: same offsets as md5_crypt
+# NOTE: same offsets as md5_crypt
_chk_offsets = (
12,6,0,
13,7,1,
@@ -161,9 +168,9 @@ _chk_offsets = (
11,
)
-#=========================================================
-#handler
-#=========================================================
+#=============================================================================
+# handler
+#=============================================================================
class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
"""This class implements the Sun-MD5-Crypt password hash, and follows the :ref:`password-hash-api`.
@@ -206,47 +213,47 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
.. versionadded:: 1.6
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
name = "sun_md5_crypt"
setting_kwds = ("salt", "rounds", "bare_salt", "salt_size")
checksum_chars = uh.HASH64_CHARS
checksum_size = 22
- #NOTE: docs say max password length is 255.
- #release 9u2
+ # NOTE: docs say max password length is 255.
+ # release 9u2
- #NOTE: not sure if original crypt has a salt size limit,
+ # NOTE: not sure if original crypt has a salt size limit,
# all instances that have been seen use 8 chars.
default_salt_size = 8
min_salt_size = 0
max_salt_size = None
salt_chars = uh.HASH64_CHARS
- default_rounds = 5000 #current passlib default
+ default_rounds = 5000 # current passlib default
min_rounds = 0
max_rounds = 4294963199 ##2**32-1-4096
- #XXX: ^ not sure what it does if past this bound... does 32 int roll over?
+ # XXX: ^ not sure what it does if past this bound... does 32 int roll over?
rounds_cost = "linear"
ident_values = (u("$md5$"), u("$md5,"))
- #=========================================================
- #instance attrs
- #=========================================================
- bare_salt = False #flag to indicate legacy hashes that lack "$$" suffix
+ #===================================================================
+ # instance attrs
+ #===================================================================
+ bare_salt = False # flag to indicate legacy hashes that lack "$$" suffix
- #=========================================================
- #constructor
- #=========================================================
+ #===================================================================
+ # constructor
+ #===================================================================
def __init__(self, bare_salt=False, **kwds):
self.bare_salt = bare_salt
super(sun_md5_crypt, self).__init__(**kwds)
- #=========================================================
- #internal helpers
- #=========================================================
+ #===================================================================
+ # internal helpers
+ #===================================================================
@classmethod
def identify(cls, hash):
hash = uh.to_unicode_for_identify(hash)
@@ -257,9 +264,9 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
hash = to_unicode(hash, "ascii", "hash")
#
- #detect if hash specifies rounds value.
- #if so, parse and validate it.
- #by end, set 'rounds' to int value, and 'tail' containing salt+chk
+ # detect if hash specifies rounds value.
+ # if so, parse and validate it.
+ # by end, set 'rounds' to int value, and 'tail' containing salt+chk
#
if hash.startswith(u("$md5$")):
rounds = 0
@@ -276,7 +283,7 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
if rstr != unicode(rounds):
raise uh.exc.ZeroPaddedRoundsError(cls)
if rounds == 0:
- #NOTE: not sure if this is forbidden by spec or not;
+ # NOTE: not sure if this is forbidden by spec or not;
# but allowing it would complicate things,
# and it should never occur anyways.
raise uh.exc.MalformedHashError(cls, "explicit zero rounds")
@@ -285,9 +292,9 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
raise uh.exc.InvalidHashError(cls)
#
- #salt/checksum separation is kinda weird,
- #to deal cleanly with some backward-compatible workarounds
- #implemented by original implementation.
+ # salt/checksum separation is kinda weird,
+ # to deal cleanly with some backward-compatible workarounds
+ # implemented by original implementation.
#
chk_idx = hash.rfind(u("$"), salt_idx)
if chk_idx == -1:
@@ -333,25 +340,25 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
hash = u("%s$%s") % (hash, chk)
return uascii_to_str(hash)
- #=========================================================
- #primary interface
- #=========================================================
- #TODO: if we're on solaris, check for native crypt() support.
- # this will require extra testing, to make sure native crypt
- # actually behaves correctly.
- # especially, when using ''-config, make sure to append '$x' to string.
+ #===================================================================
+ # primary interface
+ #===================================================================
+ # TODO: if we're on solaris, check for native crypt() support.
+ # this will require extra testing, to make sure native crypt
+ # actually behaves correctly. of particular importance:
+ # when using ""-config, make sure to append "$x" to string.
def _calc_checksum(self, secret):
- #NOTE: no reference for how sun_md5_crypt handles unicode
+ # NOTE: no reference for how sun_md5_crypt handles unicode
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
config = str_to_bascii(self.to_string(withchk=False))
return raw_sun_md5_crypt(secret, self.rounds, config).decode("ascii")
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/handlers/windows.py b/passlib/handlers/windows.py
index ec8ddcd..3bc3e4f 100644
--- a/passlib/handlers/windows.py
+++ b/passlib/handlers/windows.py
@@ -1,20 +1,19 @@
"""passlib.handlers.nthash - Microsoft Windows -related hashes"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-#site
-#libs
+# site
+# pkg
from passlib.utils import to_unicode, right_pad_string
from passlib.utils.compat import b, bytes, str_to_uascii, u, unicode, uascii_to_str
from passlib.utils.md4 import md4
import passlib.utils.handlers as uh
-#pkg
-#local
+# local
__all__ = [
"lmhash",
"nthash",
@@ -23,9 +22,9 @@ __all__ = [
"msdcc2",
]
-#=========================================================
+#=============================================================================
# lanman hash
-#=========================================================
+#=============================================================================
class lmhash(uh.HasEncodingContext, uh.StaticHandler):
"""This class implements the Lan Manager Password hash, and follows the :ref:`password-hash-api`.
@@ -44,17 +43,17 @@ class lmhash(uh.HasEncodingContext, uh.StaticHandler):
Note that while this class outputs digests in lower-case hexidecimal,
it will accept upper-case as well.
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "lmhash"
checksum_chars = uh.HEX_CHARS
checksum_size = 32
default_encoding = "cp437"
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.lower()
@@ -103,13 +102,13 @@ class lmhash(uh.HasEncodingContext, uh.StaticHandler):
return des_encrypt_block(secret[0:7], MAGIC) + \
des_encrypt_block(secret[7:14], MAGIC)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# ntlm hash
-#=========================================================
+#=============================================================================
class nthash(uh.StaticHandler):
"""This class implements the NT Password hash, and follows the :ref:`password-hash-api`.
@@ -120,16 +119,16 @@ class nthash(uh.StaticHandler):
Note that while this class outputs lower-case hexidecimal digests,
it will accept upper-case digests as well.
"""
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
name = "nthash"
checksum_chars = uh.HEX_CHARS
checksum_size = 32
- #=========================================================
+ #===================================================================
# methods
- #=========================================================
+ #===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.lower()
@@ -157,9 +156,9 @@ class nthash(uh.StaticHandler):
ret = nthash.raw(secret)
return hexlify(ret).decode("ascii") if hex else ret
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
bsd_nthash = uh.PrefixWrapper("bsd_nthash", nthash, prefix="$3$$", ident="$3$$",
doc="""The class support FreeBSD's representation of NTHASH
@@ -208,9 +207,9 @@ bsd_nthash = uh.PrefixWrapper("bsd_nthash", nthash, prefix="$3$$", ident="$3$$",
## # causes one not to match.
## return lmhash.verify(secret, lm) or nthash.verify(secret, nt)
-#=========================================================
+#=============================================================================
# msdcc v1
-#=========================================================
+#=============================================================================
class msdcc(uh.HasUserContext, uh.StaticHandler):
"""This class implements Microsoft's Domain Cached Credentials password hash,
and follows the :ref:`password-hash-api`.
@@ -256,9 +255,9 @@ class msdcc(uh.HasUserContext, uh.StaticHandler):
user = to_unicode(user, "utf-8", param="user").lower().encode("utf-16-le")
return md4(md4(secret).digest() + user).digest()
-#=========================================================
+#=============================================================================
# msdcc2 aka mscash2
-#=========================================================
+#=============================================================================
class msdcc2(uh.HasUserContext, uh.StaticHandler):
"""This class implements version 2 of Microsoft's Domain Cached Credentials
password hash, and follows the :ref:`password-hash-api`.
@@ -306,6 +305,6 @@ class msdcc2(uh.HasUserContext, uh.StaticHandler):
tmp = md4(md4(secret).digest() + user).digest()
return pbkdf2(tmp, user, 10240, 16, 'hmac-sha1')
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/hash.py b/passlib/hash.py
index 7290e11..8f1b895 100644
--- a/passlib/hash.py
+++ b/passlib/hash.py
@@ -2,7 +2,7 @@
Note
====
-This module does not actually contain any hashes. This file
+This module does not actually contain any hashes. This file
is a stub that replaces itself with a proxy object.
This proxy object (passlib.registry._PasslibRegistryProxy)
@@ -12,17 +12,17 @@ The actual implementation of the various hashes is store elsewhere,
mainly in the submodules of the ``passlib.handlers`` package.
"""
-#NOTE: could support 'non-lazy' version which just imports
-# all schemes known to list_crypt_handlers()
+# NOTE: could support 'non-lazy' version which just imports
+# all schemes known to list_crypt_handlers()
-#=========================================================
+#=============================================================================
# import proxy object and replace this module
-#=========================================================
+#=============================================================================
from passlib.registry import _proxy
import sys
sys.modules[__name__] = _proxy
-#=========================================================
-#eoc
-#=========================================================
+#=============================================================================
+# eoc
+#=============================================================================
diff --git a/passlib/hosts.py b/passlib/hosts.py
index 2594296..f6eb007 100644
--- a/passlib/hosts.py
+++ b/passlib/hosts.py
@@ -1,16 +1,16 @@
"""passlib.hosts"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import sys
from warnings import warn
-#pkg
+# pkg
from passlib.context import LazyCryptContext
from passlib.exc import PasslibRuntimeWarning
from passlib.registry import get_crypt_handler
from passlib.utils import has_crypt, unix_crypt_schemes
-#local
+# local
__all__ = [
"linux_context", "linux2_context",
"openbsd_context",
@@ -19,9 +19,9 @@ __all__ = [
"host_context",
]
-#=========================================================
+#=============================================================================
# linux support
-#=========================================================
+#=============================================================================
# known platform names - linux2
@@ -31,11 +31,11 @@ linux_context = linux2_context = LazyCryptContext(
deprecated = [ "des_crypt" ],
)
-#=========================================================
+#=============================================================================
# bsd support
-#=========================================================
+#=============================================================================
-#known platform names -
+# known platform names -
# freebsd2
# freebsd3
# freebsd4
@@ -45,7 +45,7 @@ linux_context = linux2_context = LazyCryptContext(
#
# netbsd1
-#referencing source via -http://fxr.googlebit.com
+# referencing source via -http://fxr.googlebit.com
# freebsd 6,7,8 - des, md5, bcrypt, bsd_nthash
# netbsd - des, ext, md5, bcrypt, sha1
# openbsd - des, ext, md5, bcrypt
@@ -62,9 +62,9 @@ netbsd_context = LazyCryptContext(["bcrypt", "sha1_crypt", "md5_crypt",
# XXX: include darwin in this list? it's got a BSD crypt variant,
# but that's not what it uses for user passwords.
-#=========================================================
-#current host
-#=========================================================
+#=============================================================================
+# current host
+#=============================================================================
if has_crypt:
# NOTE: this is basically mimicing the output of os crypt(),
# except that it uses passlib's (usually stronger) defaults settings,
@@ -89,27 +89,27 @@ if has_crypt:
host_context = LazyCryptContext(_iter_os_crypt_schemes())
-#=========================================================
-#other platforms
-#=========================================================
-
-#known platform strings -
-#aix3
-#aix4
-#atheos
-#beos5
-#darwin
-#generic
-#hp-ux11
-#irix5
-#irix6
-#mac
-#next3
-#os2emx
-#riscos
-#sunos5
-#unixware7
-
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# other platforms
+#=============================================================================
+
+# known platform strings -
+# aix3
+# aix4
+# atheos
+# beos5
+# darwin
+# generic
+# hp-ux11
+# irix5
+# irix6
+# mac
+# next3
+# os2emx
+# riscos
+# sunos5
+# unixware7
+
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/ifc.py b/passlib/ifc.py
index 79911fb..908890a 100644
--- a/passlib/ifc.py
+++ b/passlib/ifc.py
@@ -12,9 +12,9 @@ __all__ = [
"PasswordHash",
]
-#=====================================================
+#=============================================================================
# 2.5-3.2 compatibility helpers
-#=====================================================
+#=============================================================================
if sys.version_info >= (2,6):
from abc import ABCMeta, abstractmethod, abstractproperty
else:
@@ -35,9 +35,9 @@ def create_with_metaclass(meta):
return meta(cls.__name__, cls.__bases__, cls.__dict__.copy())
return builder
-#=====================================================
+#=============================================================================
# PasswordHash interface
-#=====================================================
+#=============================================================================
class PasswordHash(object):
"""This class describes an abstract interface which all password hashes
in Passlib adhere to. Under Python 2.6 and up, this is an actual
@@ -45,42 +45,42 @@ class PasswordHash(object):
See the Passlib docs for full documentation.
"""
- #=====================================================
+ #===================================================================
# class attributes
- #=====================================================
+ #===================================================================
- #----------------------------------
+ #---------------------------------------------------------------
# general information
- #----------------------------------
+ #---------------------------------------------------------------
##name
##setting_kwds
##context_kwds
- #----------------------------------
+ #---------------------------------------------------------------
# salt information -- if 'salt' in setting_kwds
- #----------------------------------
+ #---------------------------------------------------------------
##min_salt_size
##max_salt_size
##default_salt_size
##salt_chars
##default_salt_chars
- #----------------------------------
+ #---------------------------------------------------------------
# rounds information -- if 'rounds' in setting_kwds
- #----------------------------------
+ #---------------------------------------------------------------
##min_rounds
##max_rounds
##default_rounds
##rounds_cost
- #----------------------------------
+ #---------------------------------------------------------------
# encoding info -- if 'encoding' in context_kwds
- #----------------------------------
+ #---------------------------------------------------------------
##default_encoding
- #=====================================================
+ #===================================================================
# primary methods
- #=====================================================
+ #===================================================================
@classmethod
@abstractmethod
def encrypt(cls, secret, **setting_and_context_kwds): # pragma: no cover -- abstract method
@@ -93,9 +93,9 @@ class PasswordHash(object):
"verify secret against hash, returns True/False"
raise NotImplementedError("must be implemented by subclass")
- #=====================================================
+ #===================================================================
# additional methods
- #=====================================================
+ #===================================================================
@classmethod
@abstractmethod
def identify(cls, hash): # pragma: no cover -- abstract method
@@ -114,23 +114,23 @@ class PasswordHash(object):
"generated hash for secret, using settings from config/hash string"
raise NotImplementedError("must be implemented by subclass")
- #=====================================================
+ #===================================================================
# undocumented methods / attributes
- #=====================================================
+ #===================================================================
# the following entry points are used internally by passlib,
# and aren't documented as part of the exposed interface.
# they are subject to change between releases,
# but are documented here so there's a list of them *somewhere*.
- #----------------------------------
+ #---------------------------------------------------------------
# checksum information - defined for many hashes
- #----------------------------------
+ #---------------------------------------------------------------
## checksum_chars
## checksum_size
- #----------------------------------
+ #---------------------------------------------------------------
# CryptContext flags
- #----------------------------------
+ #---------------------------------------------------------------
# hack for bsdi_crypt: if True, causes CryptContext to only generate
# odd rounds values. assumed False if not defined.
@@ -155,9 +155,9 @@ class PasswordHash(object):
## part may change at some point.
## """
- #----------------------------------
+ #---------------------------------------------------------------
# experimental methods
- #----------------------------------
+ #---------------------------------------------------------------
##@classmethod
##def normhash(cls, hash):
@@ -182,9 +182,9 @@ class PasswordHash(object):
## components currently include checksum, salt, rounds.
## """
- #=====================================================
+ #===================================================================
# eoc
- #=====================================================
+ #===================================================================
PasswordHash = create_with_metaclass(ABCMeta)(PasswordHash)
diff --git a/passlib/registry.py b/passlib/registry.py
index 59c885e..eb0db9f 100644
--- a/passlib/registry.py
+++ b/passlib/registry.py
@@ -1,7 +1,7 @@
"""passlib.registry - registry for password hash handlers"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
# core
import re
import logging; log = logging.getLogger(__name__)
@@ -17,9 +17,9 @@ __all__ = [
"list_crypt_handlers",
]
-#=========================================================
+#=============================================================================
# proxy object used in place of 'passlib.hash' module
-#=========================================================
+#=============================================================================
class _PasslibRegistryProxy(object):
"""proxy module passlib.hash
@@ -63,9 +63,9 @@ class _PasslibRegistryProxy(object):
# create single instance - available publically as 'passlib.hash'
_proxy = _PasslibRegistryProxy()
-#=========================================================
+#=============================================================================
# internal registry state
-#=========================================================
+#=============================================================================
# singleton uses to detect omitted keywords
_UNSET = object()
@@ -158,9 +158,9 @@ _name_re = re.compile("^[a-z][a-z0-9_]+[a-z0-9]$")
_forbidden_names = frozenset(["onload", "policy", "context", "all",
"default", "none", "auto"])
-#=========================================================
+#=============================================================================
# registry frontend functions
-#=========================================================
+#=============================================================================
def _validate_handler_name(name):
"""helper to validate handler name
@@ -358,7 +358,7 @@ def list_crypt_handlers(loaded_only=False):
names.update(_locations)
return sorted(names)
-#NOTE: these two functions mainly exist just for the unittests...
+# NOTE: these two functions mainly exist just for the unittests...
def _has_crypt_handler(name, loaded_only=False):
"""check if handler name is known.
@@ -394,6 +394,6 @@ def _unload_handler_name(name, locations=True):
if locations and name in _locations:
del _locations[name]
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/tests/__main__.py b/passlib/tests/__main__.py
index 9971212..2424576 100644
--- a/passlib/tests/__main__.py
+++ b/passlib/tests/__main__.py
@@ -1,5 +1,5 @@
import os
-from nose import run
+from nose import run
run(
defaultTest=os.path.dirname(__file__),
)
diff --git a/passlib/tests/_test_bad_register.py b/passlib/tests/_test_bad_register.py
index f01e0d2..26cc6bb 100644
--- a/passlib/tests/_test_bad_register.py
+++ b/passlib/tests/_test_bad_register.py
@@ -8,8 +8,8 @@ class dummy_bad(uh.StaticHandler):
class alt_dummy_bad(uh.StaticHandler):
name = "dummy_bad"
-#NOTE: if passlib.tests is being run from symlink (eg via gaeunit),
-# this module may be imported a second time as test._test_bad_registry.
-# we don't want it to do anything in that case.
+# NOTE: if passlib.tests is being run from symlink (e.g. via gaeunit),
+# this module may be imported a second time as test._test_bad_registry.
+# we don't want it to do anything in that case.
if __name__.startswith("passlib.tests"):
register_crypt_handler(alt_dummy_bad)
diff --git a/passlib/tests/backports.py b/passlib/tests/backports.py
index bde41cb..58ce18f 100644
--- a/passlib/tests/backports.py
+++ b/passlib/tests/backports.py
@@ -1,26 +1,26 @@
"""backports of needed unittest2 features"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import logging; log = logging.getLogger(__name__)
import re
import sys
##from warnings import warn
-#site
-#pkg
+# site
+# pkg
from passlib.utils.compat import base_string_types
-#local
+# local
__all__ = [
"TestCase",
"skip", "skipIf", "skipUnless"
"catch_warnings",
]
-#=========================================================
+#=============================================================================
# import latest unittest module available
-#=========================================================
+#=============================================================================
try:
import unittest2 as unittest
ut_version = 2
@@ -35,9 +35,9 @@ except ImportError:
else:
ut_version = 2
-#=========================================================
+#=============================================================================
# backport SkipTest support using nose
-#=========================================================
+#=============================================================================
if ut_version < 2:
# used to provide replacement SkipTest() error
from nose.plugins.skip import SkipTest
@@ -74,14 +74,14 @@ else:
skipIf = unittest.skipIf
skipUnless = unittest.skipUnless
-#=========================================================
+#=============================================================================
# custom test harness
-#=========================================================
+#=============================================================================
class TestCase(unittest.TestCase):
"""backports a number of unittest2 features in TestCase"""
- #====================================================================
+ #===================================================================
# backport some methods from unittest2
- #====================================================================
+ #===================================================================
if ut_version < 2:
#----------------------------------------------------------------
@@ -210,9 +210,9 @@ class TestCase(unittest.TestCase):
msg = self._formatMessage(msg, std)
raise self.failureException(msg)
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# backport assertRegex() alias from 3.2 to 2.7/3.1
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
if not hasattr(unittest.TestCase, "assertRegex"):
if hasattr(unittest.TestCase, "assertRegexpMatches"):
# was present in 2.7/3.1 under name assertRegexpMatches
@@ -229,9 +229,9 @@ class TestCase(unittest.TestCase):
std = '%r not found in %r' % (msg, expected_regex.pattern, text)
raise self.failureException(self._formatMessage(msg, std))
- #============================================================
- #eoc
- #============================================================
+ #===================================================================
+ # eoc
+ #===================================================================
#=============================================================================
# backport catch_warnings
diff --git a/passlib/tests/test_apache.py b/passlib/tests/test_apache.py
index e2122ae..68a992f 100644
--- a/passlib/tests/test_apache.py
+++ b/passlib/tests/test_apache.py
@@ -1,33 +1,33 @@
"""tests for passlib.apache -- (c) Assurance Technologies 2008-2011"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import hashlib
from logging import getLogger
import os
import time
-#site
-#pkg
+# site
+# pkg
from passlib import apache
from passlib.utils.compat import irange, unicode
from passlib.tests.utils import TestCase, get_file, set_file, catch_warnings, ensure_mtime_changed
from passlib.utils.compat import b, bytes, u
-#module
+# module
log = getLogger(__name__)
def backdate_file_mtime(path, offset=10):
"backdate file's mtime by specified amount"
- #NOTE: this is used so we can test code which detects mtime changes,
- # without having to actually *pause* for that long.
+ # NOTE: this is used so we can test code which detects mtime changes,
+ # without having to actually *pause* for that long.
atime = os.path.getatime(path)
mtime = os.path.getmtime(path)-offset
os.utime(path, (atime, mtime))
-#=========================================================
-#htpasswd
-#=========================================================
+#=============================================================================
+# htpasswd
+#=============================================================================
class HtpasswdFileTest(TestCase):
"test HtpasswdFile class"
descriptionPrefix = "HtpasswdFile"
@@ -86,7 +86,7 @@ class HtpasswdFileTest(TestCase):
os.remove(path)
self.assertRaises(IOError, apache.HtpasswdFile, path)
- #NOTE: "default_scheme" option checked via set_password() test, among others
+ # NOTE: "default_scheme" option checked via set_password() test, among others
def test_00_from_path(self):
path = self.mktemp()
@@ -221,18 +221,18 @@ class HtpasswdFileTest(TestCase):
def test_06_save(self):
"test save()"
- #load from file
+ # load from file
path = self.mktemp()
set_file(path, self.sample_01)
ht = apache.HtpasswdFile(path)
- #make changes, check they saved
+ # make changes, check they saved
ht.delete("user1")
ht.delete("user2")
ht.save()
self.assertEqual(get_file(path), self.sample_02)
- #test save w/ no path
+ # test save w/ no path
hb = apache.HtpasswdFile(default_scheme="plaintext")
hb.set_password("user1", "pass1")
self.assertRaises(RuntimeError, hb.save)
@@ -297,13 +297,13 @@ class HtpasswdFileTest(TestCase):
self.assertRaises(TypeError, apache.HtpasswdFile.from_string,
b(''), path=None)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#htdigest
-#=========================================================
+#=============================================================================
+# htdigest
+#=============================================================================
class HtdigestFileTest(TestCase):
"test HtdigestFile class"
descriptionPrefix = "HtdigestFile"
@@ -441,29 +441,29 @@ class HtdigestFileTest(TestCase):
def test_05_load(self):
"test load()"
- #setup empty file
+ # setup empty file
path = self.mktemp()
set_file(path, "")
backdate_file_mtime(path, 5)
ha = apache.HtdigestFile(path)
self.assertEqual(ha.to_string(), b(""))
- #make changes, check load_if_changed() does nothing
+ # make changes, check load_if_changed() does nothing
ha.set_password("user1", "realm", "pass1")
ha.load_if_changed()
self.assertEqual(ha.to_string(), b('user1:realm:2a6cf53e7d8f8cf39d946dc880b14128\n'))
- #change file
+ # change file
set_file(path, self.sample_01)
ha.load_if_changed()
self.assertEqual(ha.to_string(), self.sample_01)
- #make changes, check load_if_changed overwrites them
+ # make changes, check load_if_changed overwrites them
ha.set_password("user5", "realm", "pass5")
ha.load()
self.assertEqual(ha.to_string(), self.sample_01)
- #test load w/ no path
+ # test load w/ no path
hb = apache.HtdigestFile()
self.assertRaises(RuntimeError, hb.load)
self.assertRaises(RuntimeError, hb.load_if_changed)
@@ -473,7 +473,7 @@ class HtdigestFileTest(TestCase):
hc.load(path)
self.assertEqual(hc.to_string(), self.sample_01)
- #change file, test deprecated force=False kwd
+ # change file, test deprecated force=False kwd
ensure_mtime_changed(path)
set_file(path, "")
with self.assertWarningList(r"load\(force=False\) is deprecated"):
@@ -482,18 +482,18 @@ class HtdigestFileTest(TestCase):
def test_06_save(self):
"test save()"
- #load from file
+ # load from file
path = self.mktemp()
set_file(path, self.sample_01)
ht = apache.HtdigestFile(path)
- #make changes, check they saved
+ # make changes, check they saved
ht.delete("user1", "realm")
ht.delete("user2", "realm")
ht.save()
self.assertEqual(get_file(path), self.sample_02)
- #test save w/ no path
+ # test save w/ no path
hb = apache.HtdigestFile()
hb.set_password("user1", "realm", "pass1")
self.assertRaises(RuntimeError, hb.save)
@@ -555,10 +555,10 @@ class HtdigestFileTest(TestCase):
self.assertRaises(ValueError, apache.HtdigestFile.from_string,
b('user1:pass1\n'))
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_apps.py b/passlib/tests/test_apps.py
index 5f0c10c..421f83b 100644
--- a/passlib/tests/test_apps.py
+++ b/passlib/tests/test_apps.py
@@ -1,27 +1,27 @@
"""test passlib.apps"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import logging; log = logging.getLogger(__name__)
-#site
-#pkg
+# site
+# pkg
from passlib import apps, hash as hashmod
from passlib.tests.utils import TestCase
-#module
+# module
-#=========================================================
-#test predefined app contexts
-#=========================================================
+#=============================================================================
+# test predefined app contexts
+#=============================================================================
class AppsTest(TestCase):
"perform general tests to make sure contexts work"
- #NOTE: these tests are not really comprehensive,
- # since they would do little but duplicate
- # the presets in apps.py
+ # NOTE: these tests are not really comprehensive,
+ # since they would do little but duplicate
+ # the presets in apps.py
#
- # they mainly try to ensure no typos
- # or dynamic behavior foul-ups.
+ # they mainly try to ensure no typos
+ # or dynamic behavior foul-ups.
def test_master_context(self):
ctx = apps.master_context
@@ -123,6 +123,6 @@ class AppsTest(TestCase):
]:
self.assertTrue(ctx.verify("test", hash))
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_context.py b/passlib/tests/test_context.py
index 71c17d4..85dc7d0 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -1,7 +1,7 @@
"""tests for passlib.context"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
# core
from __future__ import with_statement
from passlib.utils.compat import PY3
@@ -31,9 +31,9 @@ from passlib.registry import (register_crypt_handler_path,
get_crypt_handler,
)
# local
-#=========================================================
+#=============================================================================
# support
-#=========================================================
+#=============================================================================
here = os.path.abspath(os.path.dirname(__file__))
def merge_dicts(first, *args, **kwds):
@@ -44,22 +44,22 @@ def merge_dicts(first, *args, **kwds):
target.update(kwds)
return target
-#=========================================================
+#=============================================================================
#
-#=========================================================
+#=============================================================================
class CryptContextTest(TestCase):
descriptionPrefix = "CryptContext"
# TODO: these unittests could really use a good cleanup
# and reorganizing, to ensure they're getting everything.
- #=========================================================
+ #===================================================================
# sample configurations used in tests
- #=========================================================
+ #===================================================================
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 1 - typical configuration
- #-----------------------------------------------------
+ #---------------------------------------------------------------
sample_1_schemes = ["des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"]
sample_1_handlers = [get_crypt_handler(name) for name in sample_1_schemes]
@@ -101,9 +101,9 @@ sha512_crypt__min_rounds = 40000
""")
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 1 external files
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 1 string with '\n' linesep
sample_1_path = os.path.join(here, "sample1.cfg")
@@ -123,15 +123,15 @@ sha512_crypt__min_rounds = 40000
set_file(sample_1b_path, sample_1b_unicode)
set_file(sample_1c_path, sample_1c_bytes)
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 2 & 12 - options patch
- #-----------------------------------------------------
+ #---------------------------------------------------------------
sample_2_dict = dict(
- #using this to test full replacement of existing options
+ # using this to test full replacement of existing options
bsdi_crypt__min_rounds = 29000,
bsdi_crypt__max_rounds = 35000,
bsdi_crypt__default_rounds = 31000,
- #using this to test partial replacement of existing options
+ # using this to test partial replacement of existing options
sha512_crypt__min_rounds=45000,
)
@@ -146,9 +146,9 @@ sha512_crypt__min_rounds = 45000
# sample 2 overlayed on top of sample 1
sample_12_dict = merge_dicts(sample_1_dict, sample_2_dict)
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 3 & 123 - just changing default from sample 1
- #-----------------------------------------------------
+ #---------------------------------------------------------------
sample_3_dict = dict(
default="sha512_crypt",
)
@@ -156,9 +156,9 @@ sha512_crypt__min_rounds = 45000
# sample 3 overlayed on 2 overlayed on 1
sample_123_dict = merge_dicts(sample_12_dict, sample_3_dict)
- #-----------------------------------------------------
+ #---------------------------------------------------------------
# sample 4 - used by api tests
- #-----------------------------------------------------
+ #---------------------------------------------------------------
sample_4_dict = dict(
schemes = [ "des_crypt", "md5_crypt", "phpass", "bsdi_crypt",
"sha256_crypt"],
@@ -174,9 +174,9 @@ sha512_crypt__min_rounds = 45000
phpass__default_rounds = 7,
)
- #=========================================================
+ #===================================================================
# constructors
- #=========================================================
+ #===================================================================
def test_01_constructor(self):
"test class constructor"
@@ -291,9 +291,9 @@ sha512_crypt__min_rounds = 45000
cc1 = CryptContext(**self.sample_1_dict)
self.assertRegex(repr(cc1), "^<CryptContext at 0x[0-9a-f]+>$")
- #=========================================================
+ #===================================================================
# modifiers
- #=========================================================
+ #===================================================================
def test_10_load(self):
"test load() / load_path() method"
# NOTE: load() is the workhorse that handles all policy parsing,
@@ -395,9 +395,9 @@ sha512_crypt__min_rounds = 45000
# wrong arg type
self.assertRaises(TypeError, ctx.update, None)
- #=========================================================
+ #===================================================================
# option parsing
- #=========================================================
+ #===================================================================
def test_20_options(self):
"test basic option parsing"
def parse(**kwds):
@@ -541,7 +541,7 @@ sha512_crypt__min_rounds = 45000
admin__context__deprecated=['des_crypt', 'md5_crypt'])
# deprecating explicit default scheme should cause ValueError
-
+
# ... default listed as deprecated
self.assertRaises(ValueError, CryptContext,
schemes=['des_crypt', 'md5_crypt'],
@@ -593,7 +593,7 @@ sha512_crypt__min_rounds = 45000
self.assertEqual(getdep(cc), ["md5_crypt"])
self.assertEqual(getdep(cc, "user"), ["md5_crypt"])
self.assertEqual(getdep(cc, "admin"), [])
-
+
def test_23_default(self):
"test 'default' context option parsing"
@@ -647,9 +647,9 @@ sha512_crypt__min_rounds = 45000
self.assertEqual(parse(1000), 1000)
self.assertEqual(parse('1000'), 1000)
- #=========================================================
+ #===================================================================
# inspection & serialization
- #=========================================================
+ #===================================================================
def test_30_schemes(self):
"test schemes() method"
# NOTE: also checked under test_21
@@ -833,9 +833,9 @@ sha512_crypt__min_rounds = 45000
self.assertRegex(dump, r"# NOTE: the 'unsalted_test_hash' handler\(s\)"
r" are not registered with Passlib")
- #=========================================================
+ #===================================================================
# password hash api
- #=========================================================
+ #===================================================================
nonstring_vectors = [
(None, {}),
(None, {"scheme": "des_crypt"}),
@@ -848,7 +848,7 @@ sha512_crypt__min_rounds = 45000
handlers = [hash.md5_crypt, hash.des_crypt, hash.bsdi_crypt]
cc = CryptContext(handlers, bsdi_crypt__default_rounds=5)
- #run through handlers
+ # run through handlers
for crypt in handlers:
h = cc.encrypt("test", scheme=crypt.name)
self.assertEqual(cc.identify(h), crypt.name)
@@ -856,11 +856,11 @@ sha512_crypt__min_rounds = 45000
self.assertTrue(cc.verify('test', h))
self.assertFalse(cc.verify('notest', h))
- #test default
+ # test default
h = cc.encrypt("test")
self.assertEqual(cc.identify(h), "md5_crypt")
- #test genhash
+ # test genhash
h = cc.genhash('secret', cc.genconfig())
self.assertEqual(cc.identify(h), 'md5_crypt')
@@ -1011,7 +1011,7 @@ sha512_crypt__min_rounds = 45000
handlers = ["md5_crypt", "des_crypt", "bsdi_crypt"]
cc = CryptContext(handlers, bsdi_crypt__default_rounds=5)
- #check unknown hash
+ # check unknown hash
self.assertEqual(cc.identify('$9$232323123$1287319827'), None)
self.assertRaises(ValueError, cc.identify, '$9$232323123$1287319827', required=True)
@@ -1039,15 +1039,15 @@ sha512_crypt__min_rounds = 45000
h = hash.md5_crypt.encrypt("test")
- #check base verify
+ # check base verify
self.assertTrue(cc.verify("test", h))
self.assertTrue(not cc.verify("notest", h))
- #check verify using right alg
+ # check verify using right alg
self.assertTrue(cc.verify('test', h, scheme='md5_crypt'))
self.assertTrue(not cc.verify('notest', h, scheme='md5_crypt'))
- #check verify using wrong alg
+ # check verify using wrong alg
self.assertRaises(ValueError, cc.verify, 'test', h, scheme='bsdi_crypt')
#--------------------------------------------------------------
@@ -1082,15 +1082,15 @@ sha512_crypt__min_rounds = 45000
"test needs_update() method"
cc = CryptContext(**self.sample_4_dict)
- #check deprecated scheme
+ # check deprecated scheme
self.assertTrue(cc.needs_update('9XXD4trGYeGJA'))
self.assertFalse(cc.needs_update('$1$J8HC2RCr$HcmM.7NxB2weSvlw2FgzU0'))
- #check min rounds
+ # check min rounds
self.assertTrue(cc.needs_update('$5$rounds=1999$jD81UCoo.zI.UETs$Y7qSTQ6mTiU9qZB4fRr43wRgQq4V.5AAf7F97Pzxey/'))
self.assertFalse(cc.needs_update('$5$rounds=2000$228SSRje04cnNCaQ$YGV4RYu.5sNiBvorQDlO0WWQjyJVGKBcJXz3OtyQ2u8'))
- #check max rounds
+ # check max rounds
self.assertFalse(cc.needs_update('$5$rounds=3000$fS9iazEwTKi7QPW4$VasgBC8FqlOvD7x2HhABaMXCTh9jwHclPA9j5YQdns.'))
self.assertTrue(cc.needs_update('$5$rounds=3001$QlFHHifXvpFX4PLs$/0ekt7lSs/lOikSerQ0M/1porEHxYq7W/2hdFpxA3fA'))
@@ -1162,26 +1162,26 @@ sha512_crypt__min_rounds = 45000
"test verify_and_update()"
cc = CryptContext(**self.sample_4_dict)
- #create some hashes
+ # create some hashes
h1 = cc.encrypt("password", scheme="des_crypt")
h2 = cc.encrypt("password", scheme="sha256_crypt")
- #check bad password, deprecated hash
+ # check bad password, deprecated hash
ok, new_hash = cc.verify_and_update("wrongpass", h1)
self.assertFalse(ok)
self.assertIs(new_hash, None)
- #check bad password, good hash
+ # check bad password, good hash
ok, new_hash = cc.verify_and_update("wrongpass", h2)
self.assertFalse(ok)
self.assertIs(new_hash, None)
- #check right password, deprecated hash
+ # check right password, deprecated hash
ok, new_hash = cc.verify_and_update("password", h1)
self.assertTrue(ok)
self.assertTrue(cc.identify(new_hash), "sha256_crypt")
- #check right password, good hash
+ # check right password, good hash
ok, new_hash = cc.verify_and_update("password", h2)
self.assertTrue(ok)
self.assertIs(new_hash, None)
@@ -1211,9 +1211,9 @@ sha512_crypt__min_rounds = 45000
# bad category values
self.assertRaises(TypeError, cc.verify_and_update, 'secret', refhash, category=1)
- #=========================================================
+ #===================================================================
# rounds options
- #=========================================================
+ #===================================================================
# NOTE: the follow tests check how _CryptRecord handles
# the min/max/default/vary_rounds options, via the output of
# genconfig(). it's assumed encrypt() takes the same codepath.
@@ -1420,9 +1420,9 @@ sha512_crypt__min_rounds = 45000
self.assertEqual(min(seen), lower, "vary_rounds had wrong lower limit:")
self.assertEqual(max(seen), upper, "vary_rounds had wrong upper limit:")
- #=========================================================
+ #===================================================================
# feature tests
- #=========================================================
+ #===================================================================
def test_60_min_verify_time(self):
"test verify() honors min_verify_time"
delta = .05
@@ -1521,9 +1521,9 @@ sha512_crypt__min_rounds = 45000
self.assertRaises(ValueError, CryptContext, "sha256_crypt,md5_crypt",
deprecated="md5_crypt,auto")
- #=========================================================
+ #===================================================================
# handler deprecation detectors
- #=========================================================
+ #===================================================================
def test_62_bcrypt_update(self):
"test verify_and_update / needs_update corrects bcrypt padding"
# see issue 25.
@@ -1561,13 +1561,13 @@ sha512_crypt__min_rounds = 45000
self.assertTrue(ok)
self.assertTrue(new_hash and new_hash != even_hash)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
-#LazyCryptContext
-#=========================================================
+#=============================================================================
+# LazyCryptContext
+#=============================================================================
class dummy_2(uh.StaticHandler):
name = "dummy_2"
@@ -1610,6 +1610,6 @@ class LazyCryptContextTest(TestCase):
self.assertTrue(has_crypt_handler("dummy_2", True))
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_context_deprecated.py b/passlib/tests/test_context_deprecated.py
index b291bf4..247162f 100644
--- a/passlib/tests/test_context_deprecated.py
+++ b/passlib/tests/test_context_deprecated.py
@@ -5,23 +5,23 @@ containing the tests using the legacy CryptPolicy api.
it's being preserved here to ensure the old api doesn't break
(until Passlib 1.8, when this and the legacy api will be removed).
"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import hashlib
from logging import getLogger
import os
import time
import warnings
import sys
-#site
+# site
try:
from pkg_resources import resource_filename
except ImportError:
resource_filename = None
-#pkg
+# pkg
from passlib import hash
from passlib.context import CryptContext, CryptPolicy, LazyCryptContext
from passlib.exc import PasslibConfigWarning
@@ -34,27 +34,27 @@ from passlib.registry import (register_crypt_handler_path,
_unload_handler_name as unload_handler_name,
get_crypt_handler,
)
-#module
+# module
log = getLogger(__name__)
-#=========================================================
+#=============================================================================
#
-#=========================================================
+#=============================================================================
class CryptPolicyTest(TestCase):
"test CryptPolicy object"
- #TODO: need to test user categories w/in all this
+ # TODO: need to test user categories w/in all this
descriptionPrefix = "CryptPolicy"
- #=========================================================
- #sample crypt policies used for testing
- #=========================================================
+ #===================================================================
+ # sample crypt policies used for testing
+ #===================================================================
- #-----------------------------------------------------
- #sample 1 - average config file
- #-----------------------------------------------------
- #NOTE: copy of this is stored in file passlib/tests/sample_config_1s.cfg
+ #---------------------------------------------------------------
+ # sample 1 - average config file
+ #---------------------------------------------------------------
+ # NOTE: copy of this is stored in file passlib/tests/sample_config_1s.cfg
sample_config_1s = """\
[passlib]
schemes = des_crypt, md5_crypt, bsdi_crypt, sha512_crypt
@@ -68,11 +68,11 @@ sha512_crypt.min_rounds = 40000
sample_config_1s_path = os.path.abspath(os.path.join(
os.path.dirname(__file__), "sample_config_1s.cfg"))
if not os.path.exists(sample_config_1s_path) and resource_filename:
- #in case we're zipped up in an egg.
+ # in case we're zipped up in an egg.
sample_config_1s_path = resource_filename("passlib.tests",
"sample_config_1s.cfg")
- #make sure sample_config_1s uses \n linesep - tests rely on this
+ # make sure sample_config_1s uses \n linesep - tests rely on this
assert sample_config_1s.startswith("[passlib]\nschemes")
sample_config_1pd = dict(
@@ -108,9 +108,9 @@ sha512_crypt.min_rounds = 40000
sha512_crypt__min_rounds = 40000,
)
- #-----------------------------------------------------
- #sample 2 - partial policy & result of overlay on sample 1
- #-----------------------------------------------------
+ #---------------------------------------------------------------
+ # sample 2 - partial policy & result of overlay on sample 1
+ #---------------------------------------------------------------
sample_config_2s = """\
[passlib]
bsdi_crypt.min_rounds = 29000
@@ -120,11 +120,11 @@ sha512_crypt.min_rounds = 45000
"""
sample_config_2pd = dict(
- #using this to test full replacement of existing options
+ # using this to test full replacement of existing options
bsdi_crypt__min_rounds = 29000,
bsdi_crypt__max_rounds = 35000,
bsdi_crypt__default_rounds = 31000,
- #using this to test partial replacement of existing options
+ # using this to test partial replacement of existing options
sha512_crypt__min_rounds=45000,
)
@@ -140,9 +140,9 @@ sha512_crypt.min_rounds = 45000
sha512_crypt__min_rounds=45000,
)
- #-----------------------------------------------------
- #sample 3 - just changing default
- #-----------------------------------------------------
+ #---------------------------------------------------------------
+ # sample 3 - just changing default
+ #---------------------------------------------------------------
sample_config_3pd = dict(
default="sha512_crypt",
)
@@ -159,9 +159,9 @@ sha512_crypt.min_rounds = 45000
sha512_crypt__min_rounds=45000,
)
- #-----------------------------------------------------
- #sample 4 - category specific
- #-----------------------------------------------------
+ #---------------------------------------------------------------
+ # sample 4 - category specific
+ #---------------------------------------------------------------
sample_config_4s = """
[passlib]
schemes = sha512_crypt
@@ -181,9 +181,9 @@ admin.sha512_crypt.max_rounds = 40000
admin__sha512_crypt__max_rounds = 40000,
)
- #-----------------------------------------------------
- #sample 5 - to_string & deprecation testing
- #-----------------------------------------------------
+ #---------------------------------------------------------------
+ # sample 5 - to_string & deprecation testing
+ #---------------------------------------------------------------
sample_config_5s = sample_config_1s + """\
deprecated = des_crypt
admin__context__deprecated = des_crypt, bsdi_crypt
@@ -209,9 +209,9 @@ admin__context__deprecated = des_crypt, bsdi_crypt
"admin__context__deprecated": ["des_crypt", "bsdi_crypt"],
})
- #=========================================================
- #constructors
- #=========================================================
+ #===================================================================
+ # constructors
+ #===================================================================
def setUp(self):
TestCase.setUp(self)
warnings.filterwarnings("ignore",
@@ -228,13 +228,13 @@ admin__context__deprecated = des_crypt, bsdi_crypt
self.assertRaises(TypeError, CryptPolicy, {}, {})
self.assertRaises(TypeError, CryptPolicy, {}, dummy=1)
- #check key with too many separators is rejected
+ # check key with too many separators is rejected
self.assertRaises(TypeError, CryptPolicy,
schemes = [ "des_crypt", "md5_crypt", "bsdi_crypt", "sha512_crypt"],
bad__key__bsdi_crypt__max_rounds = 30000,
)
- #check nameless handler rejected
+ # check nameless handler rejected
class nameless(uh.StaticHandler):
name = None
self.assertRaises(ValueError, CryptPolicy, schemes=[nameless])
@@ -242,48 +242,48 @@ admin__context__deprecated = des_crypt, bsdi_crypt
# check scheme must be name or crypt handler
self.assertRaises(TypeError, CryptPolicy, schemes=[uh.StaticHandler])
- #check name conflicts are rejected
+ # check name conflicts are rejected
class dummy_1(uh.StaticHandler):
name = 'dummy_1'
self.assertRaises(KeyError, CryptPolicy, schemes=[dummy_1, dummy_1])
- #with unknown deprecated value
+ # with unknown deprecated value
self.assertRaises(KeyError, CryptPolicy,
schemes=['des_crypt'],
deprecated=['md5_crypt'])
- #with unknown default value
+ # with unknown default value
self.assertRaises(KeyError, CryptPolicy,
schemes=['des_crypt'],
default='md5_crypt')
def test_01_from_path_simple(self):
"test CryptPolicy.from_path() constructor"
- #NOTE: this is separate so it can also run under GAE
+ # NOTE: this is separate so it can also run under GAE
- #test preset stored in existing file
+ # test preset stored in existing file
path = self.sample_config_1s_path
policy = CryptPolicy.from_path(path)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test if path missing
+ # test if path missing
self.assertRaises(EnvironmentError, CryptPolicy.from_path, path + 'xxx')
def test_01_from_path(self):
"test CryptPolicy.from_path() constructor with encodings"
path = self.mktemp()
- #test "\n" linesep
+ # test "\n" linesep
set_file(path, self.sample_config_1s)
policy = CryptPolicy.from_path(path)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test "\r\n" linesep
+ # test "\r\n" linesep
set_file(path, self.sample_config_1s.replace("\n","\r\n"))
policy = CryptPolicy.from_path(path)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test with custom encoding
+ # test with custom encoding
uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
set_file(path, uc2)
policy = CryptPolicy.from_path(path, encoding="utf-16")
@@ -291,62 +291,62 @@ admin__context__deprecated = des_crypt, bsdi_crypt
def test_02_from_string(self):
"test CryptPolicy.from_string() constructor"
- #test "\n" linesep
+ # test "\n" linesep
policy = CryptPolicy.from_string(self.sample_config_1s)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test "\r\n" linesep
+ # test "\r\n" linesep
policy = CryptPolicy.from_string(
self.sample_config_1s.replace("\n","\r\n"))
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test with unicode
+ # test with unicode
data = to_unicode(self.sample_config_1s)
policy = CryptPolicy.from_string(data)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test with non-ascii-compatible encoding
+ # test with non-ascii-compatible encoding
uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
policy = CryptPolicy.from_string(uc2, encoding="utf-16")
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #test category specific options
+ # test category specific options
policy = CryptPolicy.from_string(self.sample_config_4s)
self.assertEqual(policy.to_dict(), self.sample_config_4pd)
def test_03_from_source(self):
"test CryptPolicy.from_source() constructor"
- #pass it a path
+ # pass it a path
policy = CryptPolicy.from_source(self.sample_config_1s_path)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #pass it a string
+ # pass it a string
policy = CryptPolicy.from_source(self.sample_config_1s)
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #pass it a dict (NOTE: make a copy to detect in-place modifications)
+ # pass it a dict (NOTE: make a copy to detect in-place modifications)
policy = CryptPolicy.from_source(self.sample_config_1pd.copy())
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #pass it existing policy
+ # pass it existing policy
p2 = CryptPolicy.from_source(policy)
self.assertIs(policy, p2)
- #pass it something wrong
+ # pass it something wrong
self.assertRaises(TypeError, CryptPolicy.from_source, 1)
self.assertRaises(TypeError, CryptPolicy.from_source, [])
def test_04_from_sources(self):
"test CryptPolicy.from_sources() constructor"
- #pass it empty list
+ # pass it empty list
self.assertRaises(ValueError, CryptPolicy.from_sources, [])
- #pass it one-element list
+ # pass it one-element list
policy = CryptPolicy.from_sources([self.sample_config_1s])
self.assertEqual(policy.to_dict(), self.sample_config_1pd)
- #pass multiple sources
+ # pass multiple sources
policy = CryptPolicy.from_sources(
[
self.sample_config_1s_path,
@@ -360,22 +360,22 @@ admin__context__deprecated = des_crypt, bsdi_crypt
p1 = CryptPolicy(**self.sample_config_1pd)
- #check overlaying sample 2
+ # check overlaying sample 2
p2 = p1.replace(**self.sample_config_2pd)
self.assertEqual(p2.to_dict(), self.sample_config_12pd)
- #check repeating overlay makes no change
+ # check repeating overlay makes no change
p2b = p2.replace(**self.sample_config_2pd)
self.assertEqual(p2b.to_dict(), self.sample_config_12pd)
- #check overlaying sample 3
+ # check overlaying sample 3
p3 = p2.replace(self.sample_config_3pd)
self.assertEqual(p3.to_dict(), self.sample_config_123pd)
def test_06_forbidden(self):
"test CryptPolicy() forbidden kwds"
- #salt not allowed to be set
+ # salt not allowed to be set
self.assertRaises(KeyError, CryptPolicy,
schemes=["des_crypt"],
des_crypt__salt="xx",
@@ -385,15 +385,15 @@ admin__context__deprecated = des_crypt, bsdi_crypt
all__salt="xx",
)
- #schemes not allowed for category
+ # schemes not allowed for category
self.assertRaises(KeyError, CryptPolicy,
schemes=["des_crypt"],
user__context__schemes=["md5_crypt"],
)
- #=========================================================
- #reading
- #=========================================================
+ #===================================================================
+ # reading
+ #===================================================================
def test_10_has_schemes(self):
"test has_schemes() method"
@@ -418,14 +418,14 @@ admin__context__deprecated = des_crypt, bsdi_crypt
p1 = CryptPolicy(**self.sample_config_1pd)
- #check by name
+ # check by name
self.assertIs(p1.get_handler("bsdi_crypt"), hash.bsdi_crypt)
- #check by missing name
+ # check by missing name
self.assertIs(p1.get_handler("sha256_crypt"), None)
self.assertRaises(KeyError, p1.get_handler, "sha256_crypt", required=True)
- #check default
+ # check default
self.assertIs(p1.get_handler(), hash.md5_crypt)
def test_13_get_options(self):
@@ -480,7 +480,7 @@ admin__context__deprecated = des_crypt, bsdi_crypt
self.assertFalse(pb.handler_is_deprecated(hash.bsdi_crypt))
self.assertFalse(pb.handler_is_deprecated("sha512_crypt"))
- #check categories as well
+ # check categories as well
self.assertTrue(pb.handler_is_deprecated("des_crypt", "user"))
self.assertFalse(pb.handler_is_deprecated("bsdi_crypt", "user"))
self.assertTrue(pb.handler_is_deprecated("des_crypt", "admin"))
@@ -518,9 +518,9 @@ admin__context__deprecated = des_crypt, bsdi_crypt
self.assertEqual(pd.get_min_verify_time(), .1)
self.assertEqual(pd.get_min_verify_time('admin'), .2)
- #=========================================================
- #serialization
- #=========================================================
+ #===================================================================
+ # serialization
+ #===================================================================
def test_20_iter_config(self):
"test iter_config() method"
p5 = CryptPolicy(**self.sample_config_5pd)
@@ -537,20 +537,20 @@ admin__context__deprecated = des_crypt, bsdi_crypt
def test_22_to_string(self):
"test to_string() method"
pa = CryptPolicy(**self.sample_config_5pd)
- s = pa.to_string() #NOTE: can't compare string directly, ordering etc may not match
+ s = pa.to_string() # NOTE: can't compare string directly, ordering etc may not match
pb = CryptPolicy.from_string(s)
self.assertEqual(pb.to_dict(), self.sample_config_5pd)
s = pa.to_string(encoding="latin-1")
self.assertIsInstance(s, bytes)
- #=========================================================
+ #===================================================================
#
- #=========================================================
+ #===================================================================
-#=========================================================
-#CryptContext
-#=========================================================
+#=============================================================================
+# CryptContext
+#=============================================================================
class CryptContextTest(TestCase):
"test CryptContext class"
descriptionPrefix = "CryptContext"
@@ -563,19 +563,19 @@ class CryptContextTest(TestCase):
r"The CryptContext ``policy`` keyword has been deprecated.*")
warnings.filterwarnings("ignore", ".*(CryptPolicy|context\.policy).*(has|have) been deprecated.*")
- #=========================================================
- #constructor
- #=========================================================
+ #===================================================================
+ # constructor
+ #===================================================================
def test_00_constructor(self):
"test constructor"
- #create crypt context using handlers
+ # create crypt context using handlers
cc = CryptContext([hash.md5_crypt, hash.bsdi_crypt, hash.des_crypt])
c,b,a = cc.policy.iter_handlers()
self.assertIs(a, hash.des_crypt)
self.assertIs(b, hash.bsdi_crypt)
self.assertIs(c, hash.md5_crypt)
- #create context using names
+ # create context using names
cc = CryptContext(["md5_crypt", "bsdi_crypt", "des_crypt"])
c,b,a = cc.policy.iter_handlers()
self.assertIs(a, hash.des_crypt)
@@ -615,13 +615,13 @@ class CryptContextTest(TestCase):
def test_02_no_handlers(self):
"test no handlers"
- #check constructor...
+ # check constructor...
cc = CryptContext()
self.assertRaises(KeyError, cc.identify, 'hash', required=True)
self.assertRaises(KeyError, cc.encrypt, 'secret')
self.assertRaises(KeyError, cc.verify, 'secret', 'hash')
- #check updating policy after the fact...
+ # check updating policy after the fact...
cc = CryptContext(['md5_crypt'])
p = CryptPolicy(schemes=[])
cc.policy = p
@@ -630,9 +630,9 @@ class CryptContextTest(TestCase):
self.assertRaises(KeyError, cc.encrypt, 'secret')
self.assertRaises(KeyError, cc.verify, 'secret', 'hash')
- #=========================================================
- #policy adaptation
- #=========================================================
+ #===================================================================
+ # policy adaptation
+ #===================================================================
sample_policy_1 = dict(
schemes = [ "des_crypt", "md5_crypt", "phpass", "bsdi_crypt",
"sha256_crypt"],
@@ -652,21 +652,21 @@ class CryptContextTest(TestCase):
"test hash_needs_update() method"
cc = CryptContext(**self.sample_policy_1)
- #check deprecated scheme
+ # check deprecated scheme
self.assertTrue(cc.hash_needs_update('9XXD4trGYeGJA'))
self.assertFalse(cc.hash_needs_update('$1$J8HC2RCr$HcmM.7NxB2weSvlw2FgzU0'))
- #check min rounds
+ # check min rounds
self.assertTrue(cc.hash_needs_update('$5$rounds=1999$jD81UCoo.zI.UETs$Y7qSTQ6mTiU9qZB4fRr43wRgQq4V.5AAf7F97Pzxey/'))
self.assertFalse(cc.hash_needs_update('$5$rounds=2000$228SSRje04cnNCaQ$YGV4RYu.5sNiBvorQDlO0WWQjyJVGKBcJXz3OtyQ2u8'))
- #check max rounds
+ # check max rounds
self.assertFalse(cc.hash_needs_update('$5$rounds=3000$fS9iazEwTKi7QPW4$VasgBC8FqlOvD7x2HhABaMXCTh9jwHclPA9j5YQdns.'))
self.assertTrue(cc.hash_needs_update('$5$rounds=3001$QlFHHifXvpFX4PLs$/0ekt7lSs/lOikSerQ0M/1porEHxYq7W/2hdFpxA3fA'))
- #=========================================================
+ #===================================================================
# border cases
- #=========================================================
+ #===================================================================
def test_30_nonstring_hash(self):
"test non-string hash values cause error"
#
@@ -686,13 +686,13 @@ class CryptContextTest(TestCase):
cc2 = CryptContext(["mysql323"])
self.assertRaises(TypeError, cc2.hash_needs_update, None)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#LazyCryptContext
-#=========================================================
+#=============================================================================
+# LazyCryptContext
+#=============================================================================
class dummy_2(uh.StaticHandler):
name = "dummy_2"
@@ -741,6 +741,6 @@ class LazyCryptContextTest(TestCase):
self.assertTrue(has_crypt_handler("dummy_2", True))
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_ext_django.py b/passlib/tests/test_ext_django.py
index c7cdecf..f9fd689 100644
--- a/passlib/tests/test_ext_django.py
+++ b/passlib/tests/test_ext_django.py
@@ -1,7 +1,7 @@
"""test passlib.ext.django"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
# core
import logging; log = logging.getLogger(__name__)
@@ -20,9 +20,9 @@ from passlib.tests.utils import TestCase, skipUnless, catch_warnings, TEST_MODE,
from passlib.tests.test_handlers import get_handler_case
# local
-#=========================================================
+#=============================================================================
# configure django settings for testcases
-#=========================================================
+#=============================================================================
from passlib.ext.django.utils import DJANGO_VERSION
# disable all Django integration tests under py3,
@@ -53,9 +53,9 @@ if has_django:
elif not settings.configured:
settings.configure()
-#=========================================================
+#=============================================================================
# support funcs
-#=========================================================
+#=============================================================================
# flag for update_settings() to remove specified key entirely
UNSET = object()
@@ -104,9 +104,9 @@ def create_mock_setter():
setter.popstate = popstate
return setter
-#=========================================================
+#=============================================================================
# work up stock django config
-#=========================================================
+#=============================================================================
if has_django14:
# have to modify this a little -
# all but pbkdf2_sha256 will be deprecated here,
@@ -120,14 +120,14 @@ else:
stock_config = dict(schemes=["django_salted_sha1", "django_salted_md5", "hex_md5"],
deprecated=["hex_md5"])
-#=========================================================
+#=============================================================================
# test utils
-#=========================================================
+#=============================================================================
class _ExtensionSupport(object):
"support funcs for loading/unloading extension"
- #=========================================================
+ #===================================================================
# support funcs
- #=========================================================
+ #===================================================================
@classmethod
def _iter_patch_candidates(cls):
"""helper to scan for monkeypatches.
@@ -163,9 +163,9 @@ class _ExtensionSupport(object):
if source:
yield obj, attr, source, (attr in patched)
- #=========================================================
+ #===================================================================
# verify current patch state
- #=========================================================
+ #===================================================================
def assert_unpatched(self):
"test that django is in unpatched state"
# make sure we aren't currently patched
@@ -206,9 +206,9 @@ class _ExtensionSupport(object):
self.assertEqual(mod.password_context.to_dict(resolve=True),
context.to_dict(resolve=True))
- #=========================================================
+ #===================================================================
# load / unload the extension (and verify it worked)
- #=========================================================
+ #===================================================================
_config_keys = ["PASSLIB_CONFIG", "PASSLIB_CONTEXT", "PASSLIB_GET_CATEGORY"]
def load_extension(self, check=True, **kwds):
@@ -235,9 +235,9 @@ class _ExtensionSupport(object):
# check everything's gone
self.assert_unpatched()
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class _ExtensionTest(TestCase, _ExtensionSupport):
def setUp(self):
@@ -254,9 +254,9 @@ class _ExtensionTest(TestCase, _ExtensionSupport):
# and do the same when the test exits
self.addCleanup(self.unload_extension)
-#=========================================================
+#=============================================================================
# extension tests
-#=========================================================
+#=============================================================================
class DjangoBehaviorTest(_ExtensionTest):
"tests model to verify it matches django's behavior"
descriptionPrefix = "verify django behavior"
@@ -604,9 +604,9 @@ class DjangoExtensionTest(_ExtensionTest):
"""test the ``passlib.ext.django`` plugin"""
descriptionPrefix = "passlib.ext.django plugin"
- #=========================================================
+ #===================================================================
# monkeypatch testing
- #=========================================================
+ #===================================================================
def test_00_patch_control(self):
"test set_django_password_context patch/unpatch"
@@ -699,9 +699,9 @@ class DjangoExtensionTest(_ExtensionTest):
'hash': u('v2RWkZ*************************************'),
})
- #=========================================================
+ #===================================================================
# PASSLIB_CONFIG settings
- #=========================================================
+ #===================================================================
def test_11_config_disabled(self):
"test PASSLIB_CONFIG='disabled'"
# test config=None (deprecated)
@@ -754,9 +754,9 @@ class DjangoExtensionTest(_ExtensionTest):
update_settings(PASSLIB_CONFIG="missing-preset", PASSLIB_CONTEXT=UNSET)
self.assertRaises(ValueError, __import__, 'passlib.ext.django.models')
- #=========================================================
+ #===================================================================
# PASSLIB_GET_CATEGORY setting
- #=========================================================
+ #===================================================================
def test_21_category_setting(self):
"test PASSLIB_GET_CATEGORY parameter"
# define config where rounds can be used to detect category
@@ -804,9 +804,9 @@ class DjangoExtensionTest(_ExtensionTest):
self.assertRaises(TypeError, self.load_extension, PASSLIB_CONTEXT=config,
PASSLIB_GET_CATEGORY='x')
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
# hack up the some of the real django tests to run w/ extension loaded,
# to ensure we mimic their behavior.
@@ -824,6 +824,6 @@ if has_django14:
HashersTest = skipUnless(TEST_MODE("default"),
"requires >= 'default' test mode")(HashersTest)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py
index e71d842..c18d772 100644
--- a/passlib/tests/test_handlers.py
+++ b/passlib/tests/test_handlers.py
@@ -1,25 +1,25 @@
"""passlib.tests.test_handlers - tests for passlib hash algorithms"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import hashlib
import logging; log = logging.getLogger(__name__)
import os
import warnings
-#site
-#pkg
+# site
+# pkg
from passlib import hash
from passlib.utils import repeat_string
from passlib.utils.compat import irange, PY3, u, get_method_function
from passlib.tests.utils import TestCase, HandlerCase, skipUnless, \
TEST_MODE, b, catch_warnings, UserHandlerMixin, randintgauss, EncodingHandlerMixin
-#module
+# module
-#=========================================================
+#=============================================================================
# constants & support
-#=========================================================
+#=============================================================================
# some common unicode passwords which used as test cases
UPASS_WAV = u('\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2')
@@ -39,9 +39,9 @@ def get_handler_case(scheme):
name = "%s_test" % scheme
return globals()[name]
-#=========================================================
-#apr md5 crypt
-#=========================================================
+#=============================================================================
+# apr md5 crypt
+#=============================================================================
class apr_md5_crypt_test(HandlerCase):
handler = hash.apr_md5_crypt
@@ -64,9 +64,9 @@ class apr_md5_crypt_test(HandlerCase):
'$apr1$r31.....$HqJZimcKQFAMYayBlzkrA!'
]
-#=========================================================
-#bcrypt
-#=========================================================
+#=============================================================================
+# bcrypt
+#=============================================================================
class _bcrypt_test(HandlerCase):
"base for BCrypt test cases"
handler = hash.bcrypt
@@ -175,20 +175,20 @@ class _bcrypt_test(HandlerCase):
# rounds not zero-padded (py-bcrypt rejects this, therefore so do we)
'$2a$6$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s.'
- #NOTE: salts with padding bits set are technically malformed,
+ # NOTE: salts with padding bits set are technically malformed,
# but we can reliably correct & issue a warning for that.
]
platform_crypt_support = [
("freedbsd|openbsd|netbsd", True),
- ("darwin", False),
+ ("darwin", False),
# linux - may be present via addon, e.g. debian's libpam-unix2
# solaris - depends on policy
]
- #===============================================================
+ #===================================================================
# override some methods
- #===============================================================
+ #===================================================================
def setUp(self):
# ensure builtin is enabled for duration of test.
if TEST_MODE("full") and self.backend == "builtin":
@@ -207,9 +207,9 @@ class _bcrypt_test(HandlerCase):
kwds.setdefault("rounds", 4)
super(_bcrypt_test, self).populate_settings(kwds)
- #===============================================================
+ #===================================================================
# fuzz testing
- #===============================================================
+ #===================================================================
def os_supports_ident(self, hash):
"check if OS crypt is expected to support given ident"
if hash is None:
@@ -281,9 +281,9 @@ class _bcrypt_test(HandlerCase):
# decrease default rounds for fuzz testing to speed up volume.
return randintgauss(5, 8, 6, 1)
- #===============================================================
+ #===================================================================
# custom tests
- #===============================================================
+ #===================================================================
known_incorrect_padding = [
# password, bad hash, good hash
@@ -367,15 +367,15 @@ class _bcrypt_test(HandlerCase):
self.assertEqual(bcrypt.normhash(good), good)
self.assertEqual(bcrypt.normhash("$md5$abc"), "$md5$abc")
-hash.bcrypt._no_backends_msg() #call this for coverage purposes
+hash.bcrypt._no_backends_msg() # call this for coverage purposes
-#create test cases for specific backends
+# create test cases for specific backends
bcrypt_pybcrypt_test, bcrypt_bcryptor_test, bcrypt_os_crypt_test, bcrypt_builtin_test = \
_bcrypt_test.create_backend_cases(["pybcrypt", "bcryptor", "os_crypt", "builtin"])
-#=========================================================
-#bigcrypt
-#=========================================================
+#=============================================================================
+# bigcrypt
+#=============================================================================
class bigcrypt_test(HandlerCase):
handler = hash.bigcrypt
@@ -414,9 +414,9 @@ class bigcrypt_test(HandlerCase):
self.assertRaises(ValueError, hash.bigcrypt, use_defaults=True,
checksum=u('yh4XPJGsOZ'))
-#=========================================================
-#bsdi crypt
-#=========================================================
+#=============================================================================
+# bsdi crypt
+#=============================================================================
class _bsdi_crypt_test(HandlerCase):
"test BSDiCrypt algorithm"
handler = hash.bsdi_crypt
@@ -468,9 +468,9 @@ class _bsdi_crypt_test(HandlerCase):
bsdi_crypt_os_crypt_test, bsdi_crypt_builtin_test = \
_bsdi_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
+#=============================================================================
# cisco pix
-#=========================================================
+#=============================================================================
class cisco_pix_test(UserHandlerMixin, HandlerCase):
handler = hash.cisco_pix
secret_size = 16
@@ -528,9 +528,9 @@ class cisco_pix_test(UserHandlerMixin, HandlerCase):
(UPASS_TABLE, 'CaiIvkLMu2TOHXGT'),
]
-#=========================================================
+#=============================================================================
# cisco type 7
-#=========================================================
+#=============================================================================
class cisco_type7_test(HandlerCase):
handler = hash.cisco_type7
salt_bits = 4
@@ -611,9 +611,9 @@ class cisco_type7_test(HandlerCase):
h = handler(salt=100, relaxed=True)
self.assertEqual(h.salt, 52)
-#=========================================================
+#=============================================================================
# crypt16
-#=========================================================
+#=============================================================================
class crypt16_test(HandlerCase):
handler = hash.crypt16
secret_size = 16
@@ -640,9 +640,9 @@ class crypt16_test(HandlerCase):
(UPASS_TABLE, 'YeDc9tKkkmDvwP7buzpwhoqQ'),
]
-#=========================================================
-#des crypt
-#=========================================================
+#=============================================================================
+# des crypt
+#=============================================================================
class _des_crypt_test(HandlerCase):
"test des-crypt algorithm"
handler = hash.des_crypt
@@ -688,9 +688,9 @@ class _des_crypt_test(HandlerCase):
des_crypt_os_crypt_test, des_crypt_builtin_test = \
_des_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
-#django
-#=========================================================
+#=============================================================================
+# django
+#=============================================================================
class _DjangoHelper(object):
# NOTE: not testing against Django < 1.0 since it doesn't support
# most of these hash formats.
@@ -941,9 +941,9 @@ class django_bcrypt_test(HandlerCase, _DjangoHelper):
django_bcrypt_test = skipUnless(hash.bcrypt.has_backend(),
"no bcrypt backends available")(django_bcrypt_test)
-#=========================================================
-#fshp
-#=========================================================
+#=============================================================================
+# fshp
+#=============================================================================
class fshp_test(HandlerCase):
"test fshp algorithm"
handler = hash.fshp
@@ -1023,9 +1023,9 @@ class fshp_test(HandlerCase):
self.assertRaises(ValueError, handler, variant='9', **kwds)
self.assertRaises(ValueError, handler, variant=9, **kwds)
-#=========================================================
-#hex digests
-#=========================================================
+#=============================================================================
+# hex digests
+#=============================================================================
class hex_md4_test(HandlerCase):
handler = hash.hex_md4
known_correct_hashes = [
@@ -1065,9 +1065,9 @@ class hex_sha512_test(HandlerCase):
'29caf'),
]
-#=========================================================
+#=============================================================================
# htdigest hash
-#=========================================================
+#=============================================================================
class htdigest_test(UserHandlerMixin, HandlerCase):
handler = hash.htdigest
@@ -1104,9 +1104,9 @@ class htdigest_test(UserHandlerMixin, HandlerCase):
kwds.setdefault("realm", realm)
return secret
-#=========================================================
-#ldap hashes
-#=========================================================
+#=============================================================================
+# ldap hashes
+#=============================================================================
class ldap_md5_test(HandlerCase):
handler = hash.ldap_md5
known_correct_hashes = [
@@ -1196,8 +1196,8 @@ class ldap_plaintext_test(HandlerCase):
return pwd
class _ldap_md5_crypt_test(HandlerCase):
- #NOTE: since the ldap_{crypt} handlers are all wrappers,
- # don't need separate test. this is just to test the codebase end-to-end
+ # NOTE: since the ldap_{crypt} handlers are all wrappers, don't need
+ # separate test; this is just to test the codebase end-to-end
handler = hash.ldap_md5_crypt
known_correct_hashes = [
@@ -1242,11 +1242,11 @@ class _ldap_sha1_crypt_test(HandlerCase):
ldap_sha1_crypt_os_crypt_test, = _ldap_sha1_crypt_test.create_backend_cases(["os_crypt"])
-#=========================================================
-#ldap_pbkdf2_{digest}
-#=========================================================
-#NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs,
-# they don't extensive separate testing.
+#=============================================================================
+# ldap_pbkdf2_{digest}
+#=============================================================================
+# NOTE: since these are all wrappers for the pbkdf2_{digest} hasehs,
+# they don't extensive separate testing.
class ldap_pbkdf2_test(TestCase):
@@ -1276,9 +1276,9 @@ class ldap_pbkdf2_test(TestCase):
)
)
-#=========================================================
+#=============================================================================
# lanman
-#=========================================================
+#=============================================================================
class lmhash_test(EncodingHandlerMixin, HandlerCase):
handler = hash.lmhash
secret_size = 14
@@ -1328,9 +1328,9 @@ class lmhash_test(EncodingHandlerMixin, HandlerCase):
self.assertEqual(lmhash.raw(secret, **kwds), data)
self.assertRaises(TypeError, lmhash.raw, 1)
-#=========================================================
-#md5 crypt
-#=========================================================
+#=============================================================================
+# md5 crypt
+#=============================================================================
class _md5_crypt_test(HandlerCase):
handler = hash.md5_crypt
@@ -1380,9 +1380,9 @@ class _md5_crypt_test(HandlerCase):
md5_crypt_os_crypt_test, md5_crypt_builtin_test = \
_md5_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
+#=============================================================================
# msdcc 1 & 2
-#=========================================================
+#=============================================================================
class msdcc_test(UserHandlerMixin, HandlerCase):
handler = hash.msdcc
user_case_insensitive = True
@@ -1473,9 +1473,9 @@ class msdcc2_test(UserHandlerMixin, HandlerCase):
((UPASS_TABLE, 'bob'), 'cad511dc9edefcf69201da72efb6bb55'),
]
-#=========================================================
+#=============================================================================
# mssql 2000 & 2005
-#=========================================================
+#=============================================================================
class mssql2000_test(HandlerCase):
handler = hash.mssql2000
secret_case_insensitive = "verify-only"
@@ -1655,9 +1655,9 @@ class mssql2005_test(HandlerCase):
'0x010036D726AE86G34E97F20B198ACD219D60B446AC5E48C54F30',
]
-#=========================================================
+#=============================================================================
# mysql 323 & 41
-#=========================================================
+#=============================================================================
class mysql323_test(HandlerCase):
handler = hash.mysql323
@@ -1707,13 +1707,13 @@ class mysql41_test(HandlerCase):
(UPASS_TABLE, '*E7AFE21A9CFA2FC9D15D942AE8FB5C240FE5837B'),
]
known_unidentified_hashes = [
- #bad char in otherwise correct hash
+ # bad char in otherwise correct hash
'*6Z8989366EAF75BB670AD8EA7A7FC1176A95CEF4',
]
-#=========================================================
+#=============================================================================
# NTHASH
-#=========================================================
+#=============================================================================
class nthash_test(HandlerCase):
handler = hash.nthash
@@ -1745,7 +1745,7 @@ class nthash_test(HandlerCase):
]
known_unidentified_hashes = [
- #bad char in otherwise correct hash
+ # bad char in otherwise correct hash
'7f8fe03093cc84b267b109625f6bbfxb',
]
@@ -1758,13 +1758,13 @@ class bsd_nthash_test(HandlerCase):
]
known_unidentified_hashes = [
- #bad char in otherwise correct hash --\/
+ # bad char in otherwise correct hash --\/
'$3$$7f8fe03093cc84b267b109625f6bbfxb',
]
-#=========================================================
-#oracle 10 & 11
-#=========================================================
+#=============================================================================
+# oracle 10 & 11
+#=============================================================================
class oracle10_test(UserHandlerMixin, HandlerCase):
handler = hash.oracle10
secret_case_insensitive = True
@@ -1830,9 +1830,9 @@ class oracle11_test(HandlerCase):
(UPASS_TABLE, 'S:51586343E429A6DF024B8F242F2E9F8507B1096FACD422E29142AA4974B0'),
]
-#=========================================================
-#pbkdf2 hashes
-#=========================================================
+#=============================================================================
+# pbkdf2 hashes
+#=============================================================================
class atlassian_pbkdf2_sha1_test(HandlerCase):
handler = hash.atlassian_pbkdf2_sha1
@@ -1955,9 +1955,9 @@ class grub_pbkdf2_sha512_test(HandlerCase):
]
-#=========================================================
-#PHPass Portable Crypt
-#=========================================================
+#=============================================================================
+# PHPass Portable Crypt
+#=============================================================================
class phpass_test(HandlerCase):
handler = hash.phpass
@@ -1966,7 +1966,7 @@ class phpass_test(HandlerCase):
# from official 0.3 implementation
# http://www.openwall.com/phpass/
#
- ('test12345', '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'), #from the source
+ ('test12345', '$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r.L0'), # from the source
#
# from JTR 1.7.9
@@ -1995,9 +1995,9 @@ class phpass_test(HandlerCase):
'$P$9IQRaTwmfeRo7ud9Fh4E2PdI0S3r!L0',
]
-#=========================================================
-#plaintext
-#=========================================================
+#=============================================================================
+# plaintext
+#=============================================================================
class plaintext_test(HandlerCase):
# TODO: integrate EncodingHandlerMixin
handler = hash.plaintext
@@ -2012,9 +2012,9 @@ class plaintext_test(HandlerCase):
(PASS_TABLE_UTF8, UPASS_TABLE if PY3 else PASS_TABLE_UTF8),
]
-#=========================================================
-#postgres_md5
-#=========================================================
+#=============================================================================
+# postgres_md5
+#=============================================================================
class postgres_md5_test(UserHandlerMixin, HandlerCase):
handler = hash.postgres_md5
known_correct_hashes = [
@@ -2039,9 +2039,9 @@ class postgres_md5_test(UserHandlerMixin, HandlerCase):
'md54zc31989b20437833f697e485811254b',
]
-#=========================================================
+#=============================================================================
# scram hash
-#=========================================================
+#=============================================================================
class scram_test(HandlerCase):
handler = hash.scram
@@ -2304,9 +2304,9 @@ class scram_test(HandlerCase):
self.assertRaises(ValueError, vfull, 'pencil', h)
self.assertRaises(ValueError, vfull, 'tape', h)
-#=========================================================
+#=============================================================================
# (netbsd's) sha1 crypt
-#=========================================================
+#=============================================================================
class _sha1_crypt_test(HandlerCase):
handler = hash.sha1_crypt
@@ -2341,13 +2341,13 @@ class _sha1_crypt_test(HandlerCase):
sha1_crypt_os_crypt_test, sha1_crypt_builtin_test = \
_sha1_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
-#roundup
-#=========================================================
+#=============================================================================
+# roundup
+#=============================================================================
-#NOTE: all roundup hashes use PrefixWrapper,
-# so there's nothing natively to test.
-# so we just have a few quick cases...
+# NOTE: all roundup hashes use PrefixWrapper,
+# so there's nothing natively to test.
+# so we just have a few quick cases...
from passlib.handlers import roundup
class RoundupTest(TestCase):
@@ -2382,9 +2382,9 @@ class RoundupTest(TestCase):
"sekrit",
'{PBKDF2}5000$7BvbBq.EZzz/O0HuwX3iP.nAG3s$g3oPnFFaga2BJaX5PoPRljl4XIE')
-#=========================================================
-#sha256-crypt
-#=========================================================
+#=============================================================================
+# sha256-crypt
+#=============================================================================
class _sha256_crypt_test(HandlerCase):
handler = hash.sha256_crypt
@@ -2470,7 +2470,7 @@ class _sha256_crypt_test(HandlerCase):
filter_config_warnings = True # rounds too low, salt too small
platform_crypt_support = [
- ("freebsd(9|1\d)|linux", True),
+ ("freebsd(9|1\d)|linux", True),
("freebsd8", None), # added in freebsd 8.3
("freebsd|openbsd|netbsd|darwin", False),
# solaris - depends on policy
@@ -2479,9 +2479,9 @@ class _sha256_crypt_test(HandlerCase):
sha256_crypt_os_crypt_test, sha256_crypt_builtin_test = \
_sha256_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
-#test sha512-crypt
-#=========================================================
+#=============================================================================
+# test sha512-crypt
+#=============================================================================
class _sha512_crypt_test(HandlerCase):
handler = hash.sha512_crypt
@@ -2509,9 +2509,9 @@ class _sha512_crypt_test(HandlerCase):
]
known_malformed_hashes = [
- #zero-padded rounds
+ # zero-padded rounds
'$6$rounds=011021$KsvQipYPWpr93wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1',
- #bad char in otherwise correct hash
+ # bad char in otherwise correct hash
'$6$rounds=11021$KsvQipYPWpr9:wWP$v7xjI4X6vyVptJjB1Y02vZC5SaSijBkGmq1uJhPr3cvqvvkd42Xvo48yLVPFt8dvhCsnlUgpX.//Cxn91H4qy1',
]
@@ -2560,9 +2560,9 @@ class _sha512_crypt_test(HandlerCase):
sha512_crypt_os_crypt_test, sha512_crypt_builtin_test = \
_sha512_crypt_test.create_backend_cases(["os_crypt","builtin"])
-#=========================================================
-#sun md5 crypt
-#=========================================================
+#=============================================================================
+# sun md5 crypt
+#=============================================================================
class sun_md5_crypt_test(HandlerCase):
handler = hash.sun_md5_crypt
@@ -2657,11 +2657,11 @@ class sun_md5_crypt_test(HandlerCase):
"$md5$RPgLa6IJ$WTvAlUJ7MqH5xak2FMEwS/.",
# 2+ "$" at end of salt in config
- #NOTE: not sure what correct behavior is, so forbidding format for now.
+ # NOTE: not sure what correct behavior is, so forbidding format for now.
"$md5$3UqYqndY$$",
# 3+ "$" at end of salt in hash
- #NOTE: not sure what correct behavior is, so forbidding format for now.
+ # NOTE: not sure what correct behavior is, so forbidding format for now.
"$md5$RPgLa6IJ$$$WTvAlUJ7MqH5xak2FMEwS/",
]
@@ -2678,9 +2678,9 @@ class sun_md5_crypt_test(HandlerCase):
raise ValueError("pretending '$.' hash is config string")
return self.handler.verify(secret, hash)
-#=========================================================
-#unix disabled / fallback
-#=========================================================
+#=============================================================================
+# unix disabled / fallback
+#=============================================================================
class unix_disabled_test(HandlerCase):
handler = hash.unix_disabled
# accepts_all_hashes = True # TODO: turn this off.
@@ -2757,6 +2757,6 @@ class unix_fallback_test(HandlerCase):
# use hash if provided and valid
self.assertEqual(handler.genhash("stub", "!asd"), "!asd")
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/tests/test_hosts.py b/passlib/tests/test_hosts.py
index aebe28e..b01a108 100644
--- a/passlib/tests/test_hosts.py
+++ b/passlib/tests/test_hosts.py
@@ -1,29 +1,29 @@
"""test passlib.hosts"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import logging; log = logging.getLogger(__name__)
import warnings
-#site
-#pkg
+# site
+# pkg
from passlib import hosts, hash as hashmod
from passlib.utils import unix_crypt_schemes
from passlib.tests.utils import TestCase
-#module
+# module
-#=========================================================
-#test predefined app contexts
-#=========================================================
+#=============================================================================
+# test predefined app contexts
+#=============================================================================
class HostsTest(TestCase):
"perform general tests to make sure contexts work"
- #NOTE: these tests are not really comprehensive,
- # since they would do little but duplicate
- # the presets in apps.py
+ # NOTE: these tests are not really comprehensive,
+ # since they would do little but duplicate
+ # the presets in apps.py
#
- # they mainly try to ensure no typos
- # or dynamic behavior foul-ups.
+ # they mainly try to ensure no typos
+ # or dynamic behavior foul-ups.
def check_unix_disabled(self, ctx):
for hash in [
@@ -93,6 +93,6 @@ class HostsTest(TestCase):
if scheme in schemes:
self.assertTrue(ctx.verify("test", hash))
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_registry.py b/passlib/tests/test_registry.py
index 87c994f..bc910b5 100644
--- a/passlib/tests/test_registry.py
+++ b/passlib/tests/test_registry.py
@@ -1,32 +1,32 @@
"""tests for passlib.pwhash -- (c) Assurance Technologies 2003-2009"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import hashlib
from logging import getLogger
import os
import time
import warnings
import sys
-#site
-#pkg
+# site
+# pkg
from passlib import hash, registry
from passlib.registry import register_crypt_handler, register_crypt_handler_path, \
get_crypt_handler, list_crypt_handlers, _unload_handler_name as unload_handler_name
import passlib.utils.handlers as uh
from passlib.tests.utils import TestCase, catch_warnings
-#module
+# module
log = getLogger(__name__)
-#=========================================================
-#dummy handlers
+#=============================================================================
+# dummy handlers
#
-#NOTE: these are defined outside of test case
-# since they're used by test_register_crypt_handler_path(),
-# which needs them to be available as module globals.
-#=========================================================
+# NOTE: these are defined outside of test case
+# since they're used by test_register_crypt_handler_path(),
+# which needs them to be available as module globals.
+#=============================================================================
class dummy_0(uh.StaticHandler):
name = "dummy_0"
@@ -35,9 +35,9 @@ class alt_dummy_0(uh.StaticHandler):
dummy_x = 1
-#=========================================================
-#test registry
-#=========================================================
+#=============================================================================
+# test registry
+#=============================================================================
class RegistryTest(TestCase):
descriptionPrefix = "passlib registry"
@@ -48,17 +48,17 @@ class RegistryTest(TestCase):
def test_hash_proxy(self):
"test passlib.hash proxy object"
- #check dir works
+ # check dir works
dir(hash)
- #check repr works
+ # check repr works
repr(hash)
- #check non-existent attrs raise error
+ # check non-existent attrs raise error
self.assertRaises(AttributeError, getattr, hash, 'fooey')
- #GAE tries to set __loader__,
- #make sure that doesn't call register_crypt_handler.
+ # GAE tries to set __loader__,
+ # make sure that doesn't call register_crypt_handler.
old = getattr(hash, "__loader__", None)
test = object()
hash.__loader__ = test
@@ -70,21 +70,21 @@ class RegistryTest(TestCase):
hash.__loader__ = old
self.assertIs(hash.__loader__, old)
- #check storing attr calls register_crypt_handler
+ # check storing attr calls register_crypt_handler
class dummy_1(uh.StaticHandler):
name = "dummy_1"
hash.dummy_1 = dummy_1
self.assertIs(get_crypt_handler("dummy_1"), dummy_1)
- #check storing under wrong name results in error
+ # check storing under wrong name results in error
self.assertRaises(ValueError, setattr, hash, "dummy_1x", dummy_1)
def test_register_crypt_handler_path(self):
"test register_crypt_handler_path()"
- #NOTE: this messes w/ internals of registry, shouldn't be used publically.
+ # NOTE: this messes w/ internals of registry, shouldn't be used publically.
paths = registry._locations
- #check namespace is clear
+ # check namespace is clear
self.assertTrue('dummy_0' not in paths)
self.assertFalse(hasattr(hash, 'dummy_0'))
@@ -96,7 +96,7 @@ class RegistryTest(TestCase):
self.assertRaises(ValueError, register_crypt_handler_path,
"dummy_0", __name__ + ":dummy_0.xxx")
- #try lazy load
+ # try lazy load
register_crypt_handler_path('dummy_0', __name__)
self.assertTrue('dummy_0' in list_crypt_handlers())
self.assertTrue('dummy_0' not in list_crypt_handlers(loaded_only=True))
@@ -104,20 +104,20 @@ class RegistryTest(TestCase):
self.assertTrue('dummy_0' in list_crypt_handlers(loaded_only=True))
unload_handler_name('dummy_0')
- #try lazy load w/ alt
+ # try lazy load w/ alt
register_crypt_handler_path('dummy_0', __name__ + ':alt_dummy_0')
self.assertIs(hash.dummy_0, alt_dummy_0)
unload_handler_name('dummy_0')
- #check lazy load w/ wrong type fails
+ # check lazy load w/ wrong type fails
register_crypt_handler_path('dummy_x', __name__)
self.assertRaises(TypeError, get_crypt_handler, 'dummy_x')
- #check lazy load w/ wrong name fails
+ # check lazy load w/ wrong name fails
register_crypt_handler_path('alt_dummy_0', __name__)
self.assertRaises(ValueError, get_crypt_handler, "alt_dummy_0")
- #TODO: check lazy load which calls register_crypt_handler (warning should be issued)
+ # TODO: check lazy load which calls register_crypt_handler (warning should be issued)
sys.modules.pop("passlib.tests._test_bad_register", None)
register_crypt_handler_path("dummy_bad", "passlib.tests._test_bad_register")
with catch_warnings():
@@ -181,6 +181,6 @@ class RegistryTest(TestCase):
register_crypt_handler_path('dummy_0', __name__)
self.assertIs(get_crypt_handler("DUMMY-0"), dummy_0)
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 6a64b98..67834a0 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -1,16 +1,16 @@
"""tests for passlib.util"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
from binascii import hexlify, unhexlify
import sys
import random
import warnings
-#site
-#pkg
-#module
+# site
+# pkg
+# module
from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY2, PY3, u, \
unicode, join_bytes, SUPPORTS_DIR_METHOD
from passlib.tests.utils import TestCase, catch_warnings
@@ -18,13 +18,13 @@ from passlib.tests.utils import TestCase, catch_warnings
def hb(source):
return unhexlify(b(source))
-#=========================================================
-#byte funcs
-#=========================================================
+#=============================================================================
+# byte funcs
+#=============================================================================
class MiscTest(TestCase):
"tests various parts of utils module"
- #NOTE: could test xor_bytes(), but it's exercised well enough by pbkdf2 test
+ # NOTE: could test xor_bytes(), but it's exercised well enough by pbkdf2 test
def test_compat(self):
"test compat's lazymodule"
@@ -109,34 +109,34 @@ class MiscTest(TestCase):
def f(*a,**k):
return getrandstr(rng, *a, **k)
- #count 0
+ # count 0
self.assertEqual(f('abc',0), '')
- #count <0
+ # count <0
self.assertRaises(ValueError, f, 'abc', -1)
- #letters 0
+ # letters 0
self.assertRaises(ValueError, f, '', 0)
- #letters 1
+ # letters 1
self.assertEqual(f('a',5), 'aaaaa')
- #letters
+ # letters
x = f(u('abc'), 16)
y = f(u('abc'), 16)
self.assertIsInstance(x, unicode)
self.assertNotEqual(x,y)
self.assertEqual(sorted(set(x)), [u('a'),u('b'),u('c')])
- #bytes
+ # bytes
x = f(b('abc'), 16)
y = f(b('abc'), 16)
self.assertIsInstance(x, bytes)
self.assertNotEqual(x,y)
- #NOTE: decoding this due to py3 bytes
+ # NOTE: decoding this due to py3 bytes
self.assertEqual(sorted(set(x.decode("ascii"))), [u('a'),u('b'),u('c')])
- #generate_password
+ # generate_password
from passlib.utils import generate_password
self.assertEqual(len(generate_password(15)), 15)
@@ -289,7 +289,7 @@ class MiscTest(TestCase):
## supplied = incorrect * m
## def test():
## self.assertFalse(consteq(supplied,correct))
- ## #self.assertFalse(supplied == correct)
+ ## ##self.assertFalse(supplied == correct)
## times.append(timeit.timeit(test, number=100000))
## chars.append(len(supplied))
## # output for wolfram alpha
@@ -391,9 +391,9 @@ class MiscTest(TestCase):
self.assertEqual(splitcomma(" a , b"), ['a', 'b'])
self.assertEqual(splitcomma(" a, b, "), ['a', 'b'])
-#=========================================================
-#byte/unicode helpers
-#=========================================================
+#=============================================================================
+# byte/unicode helpers
+#=============================================================================
class CodecTest(TestCase):
"tests bytes/unicode helpers in passlib.utils"
@@ -417,28 +417,28 @@ class CodecTest(TestCase):
"test to_bytes()"
from passlib.utils import to_bytes
- #check unicode inputs
+ # check unicode inputs
self.assertEqual(to_bytes(u('abc')), b('abc'))
self.assertEqual(to_bytes(u('\x00\xff')), b('\x00\xc3\xbf'))
- #check unicode w/ encodings
+ # check unicode w/ encodings
self.assertEqual(to_bytes(u('\x00\xff'), 'latin-1'), b('\x00\xff'))
self.assertRaises(ValueError, to_bytes, u('\x00\xff'), 'ascii')
- #check bytes inputs
+ # check bytes inputs
self.assertEqual(to_bytes(b('abc')), b('abc'))
self.assertEqual(to_bytes(b('\x00\xff')), b('\x00\xff'))
self.assertEqual(to_bytes(b('\x00\xc3\xbf')), b('\x00\xc3\xbf'))
- #check byte inputs ignores enocding
+ # check byte inputs ignores enocding
self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1"),
b('\x00\xc3\xbf'))
- #check bytes transcoding
+ # check bytes transcoding
self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1", "", "utf-8"),
b('\x00\xff'))
- #check other
+ # check other
self.assertRaises(AssertionError, to_bytes, 'abc', None)
self.assertRaises(TypeError, to_bytes, None)
@@ -446,21 +446,21 @@ class CodecTest(TestCase):
"test to_unicode()"
from passlib.utils import to_unicode
- #check unicode inputs
+ # check unicode inputs
self.assertEqual(to_unicode(u('abc')), u('abc'))
self.assertEqual(to_unicode(u('\x00\xff')), u('\x00\xff'))
- #check unicode input ignores encoding
+ # check unicode input ignores encoding
self.assertEqual(to_unicode(u('\x00\xff'), "ascii"), u('\x00\xff'))
- #check bytes input
+ # check bytes input
self.assertEqual(to_unicode(b('abc')), u('abc'))
self.assertEqual(to_unicode(b('\x00\xc3\xbf')), u('\x00\xff'))
self.assertEqual(to_unicode(b('\x00\xff'), 'latin-1'),
u('\x00\xff'))
self.assertRaises(ValueError, to_unicode, b('\x00\xff'))
- #check other
+ # check other
self.assertRaises(AssertionError, to_unicode, 'abc', None)
self.assertRaises(TypeError, to_unicode, None)
@@ -519,9 +519,9 @@ class CodecTest(TestCase):
self.assertFalse(is_same_codec("ascii", "utf-8"))
-#=========================================================
+#=============================================================================
# base64engine
-#=========================================================
+#=============================================================================
class Base64EngineTest(TestCase):
"test standalone parts of Base64Engine"
# NOTE: most Base64Engine testing done via _Base64Test subclasses below.
@@ -548,9 +548,9 @@ class Base64EngineTest(TestCase):
class _Base64Test(TestCase):
"common tests for all Base64Engine instances"
- #=========================================================
+ #===================================================================
# class attrs
- #=========================================================
+ #===================================================================
# Base64Engine instance to test
engine = None
@@ -569,9 +569,9 @@ class _Base64Test(TestCase):
"generate byte string from offsets"
return join_bytes(self.engine.bytemap[o:o+1] for o in offsets)
- #=========================================================
+ #===================================================================
# test encode_bytes
- #=========================================================
+ #===================================================================
def test_encode_bytes(self):
"test encode_bytes() against reference inputs"
engine = self.engine
@@ -587,9 +587,9 @@ class _Base64Test(TestCase):
self.assertRaises(TypeError, encode, u('\x00'))
self.assertRaises(TypeError, encode, None)
- #=========================================================
+ #===================================================================
# test decode_bytes
- #=========================================================
+ #===================================================================
def test_decode_bytes(self):
"test decode_bytes() against reference inputs"
engine = self.engine
@@ -641,9 +641,9 @@ class _Base64Test(TestCase):
self.assertRaises(TypeError, decode, engine.charmap[:4])
self.assertRaises(TypeError, decode, None)
- #=========================================================
+ #===================================================================
# encode_bytes+decode_bytes
- #=========================================================
+ #===================================================================
def test_codec(self):
"test encode_bytes/decode_bytes against random data"
engine = self.engine
@@ -722,9 +722,9 @@ class _Base64Test(TestCase):
self.assertEqual(result, rdata)
i += 1
- #=========================================================
+ #===================================================================
# test transposed encode/decode - encoding independant
- #=========================================================
+ #===================================================================
# NOTE: these tests assume normal encode/decode has been tested elsewhere.
transposed = [
@@ -764,9 +764,9 @@ class _Base64Test(TestCase):
self.assertRaises(TypeError, engine.decode_transposed_bytes, tmp,
offsets)
- #=========================================================
+ #===================================================================
# test 6bit handling
- #=========================================================
+ #===================================================================
def check_int_pair(self, bits, encoded_pairs):
"helper to check encode_intXX & decode_intXX functions"
engine = self.engine
@@ -854,9 +854,9 @@ class _Base64Test(TestCase):
self.assertEqual(encode(value), data)
self.assertEqual(decode(data), value)
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
# NOTE: testing H64 & H64Big should be sufficient to verify
# that Base64Engine() works in general.
@@ -868,7 +868,7 @@ class H64_Test(_Base64Test):
descriptionPrefix = "h64 codec"
encoded_data = [
- #test lengths 0..6 to ensure tail is encoded properly
+ # test lengths 0..6 to ensure tail is encoded properly
(b(""),b("")),
(b("\x55"),b("J/")),
(b("\x55\xaa"),b("Jd8")),
@@ -877,7 +877,7 @@ class H64_Test(_Base64Test):
(b("\x55\xaa\x55\xaa\x55"),b("JdOJeK3")),
(b("\x55\xaa\x55\xaa\x55\xaa"),b("JdOJeKZe")),
- #test padding bits are null
+ # test padding bits are null
(b("\x55\xaa\x55\xaf"),b("JdOJj0")), # len = 1 mod 3
(b("\x55\xaa\x55\xaa\x5f"),b("JdOJey3")), # len = 2 mod 3
]
@@ -893,7 +893,7 @@ class H64Big_Test(_Base64Test):
descriptionPrefix = "h64big codec"
encoded_data = [
- #test lengths 0..6 to ensure tail is encoded properly
+ # test lengths 0..6 to ensure tail is encoded properly
(b(""),b("")),
(b("\x55"),b("JE")),
(b("\x55\xaa"),b("JOc")),
@@ -902,7 +902,7 @@ class H64Big_Test(_Base64Test):
(b("\x55\xaa\x55\xaa\x55"),b("JOdJeZI")),
(b("\x55\xaa\x55\xaa\x55\xaa"),b("JOdJeZKe")),
- #test padding bits are null
+ # test padding bits are null
(b("\x55\xaa\x55\xaf"),b("JOdJfk")), # len = 1 mod 3
(b("\x55\xaa\x55\xaa\x5f"),b("JOdJeZw")), # len = 2 mod 3
]
@@ -912,6 +912,6 @@ class H64Big_Test(_Base64Test):
(b("z."), 4032, 12),
]
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_utils_crypto.py b/passlib/tests/test_utils_crypto.py
index bbf4146..9284e22 100644
--- a/passlib/tests/test_utils_crypto.py
+++ b/passlib/tests/test_utils_crypto.py
@@ -1,35 +1,35 @@
"""tests for passlib.utils.(des|pbkdf2|md4)"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
from binascii import hexlify, unhexlify
import hashlib
import hmac
import sys
import random
import warnings
-#site
+# site
try:
import M2Crypto
except ImportError:
M2Crypto = None
-#pkg
-#module
+# pkg
+# module
from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY2, PY3, u, \
unicode, join_bytes, PYPY, JYTHON
from passlib.tests.utils import TestCase, TEST_MODE, catch_warnings, skipUnless, skipIf
-#=========================================================
+#=============================================================================
# support
-#=========================================================
+#=============================================================================
def hb(source):
return unhexlify(b(source))
-#=========================================================
+#=============================================================================
# test assorted crypto helpers
-#=========================================================
+#=============================================================================
class CryptoTest(TestCase):
"test various crypto functions"
@@ -77,9 +77,9 @@ class CryptoTest(TestCase):
# TODO: write full test of get_prf(), currently relying on pbkdf2 testing
-#=========================================================
-#test DES routines
-#=========================================================
+#=============================================================================
+# test DES routines
+#=============================================================================
class DesTest(TestCase):
descriptionPrefix = "DES"
@@ -128,7 +128,7 @@ class DesTest(TestCase):
_KDATA_MASK, INT_56_MASK
# make sure test vectors are preserved (sans parity bits)
- # uses ints, bytes are tested under #02
+ # uses ints, bytes are tested under # 02
for key1, _, _ in self.des_test_vectors:
key2 = shrink_des_key(key1)
key3 = expand_des_key(key2)
@@ -153,7 +153,7 @@ class DesTest(TestCase):
from passlib.utils import random, getrandbytes
# make sure reverse works for some random keys
- # uses bytes, ints are tested under #01
+ # uses bytes, ints are tested under # 01
for i in range(20):
key1 = getrandbytes(random, 7)
key2 = expand_des_key(key1)
@@ -256,9 +256,9 @@ class DesTest(TestCase):
# check invalid rounds
self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, 0, rounds=0)
-#=========================================================
+#=============================================================================
# test pure-python MD4 implementation
-#=========================================================
+#=============================================================================
from passlib.utils.md4 import _has_native_md4
has_native_md4 = _has_native_md4()
@@ -274,7 +274,7 @@ class _MD4_Test(TestCase):
vectors = [
# input -> hex digest
- #test vectors from http://www.faqs.org/rfcs/rfc1320.html - A.5
+ # test vectors from http://www.faqs.org/rfcs/rfc1320.html - A.5
(b(""), "31d6cfe0d16ae931b73c59d7e0c089c0"),
(b("a"), "bde52cb31de33e46245e05fbdbd6fb24"),
(b("abc"), "a448017aaf21d8525fc10ae87aa6729d"),
@@ -290,8 +290,8 @@ class _MD4_Test(TestCase):
h = md4(b(''))
self.assertEqual(h.hexdigest(), "31d6cfe0d16ae931b73c59d7e0c089c0")
- #NOTE: under py2, hashlib methods try to encode to ascii,
- # though shouldn't rely on that.
+ # NOTE: under py2, hashlib methods try to encode to ascii,
+ # though shouldn't rely on that.
if PY3 or self._disable_native:
self.assertRaises(TypeError, h.update, u('x'))
@@ -338,9 +338,9 @@ class MD4_Builtin_Test(_MD4_Test):
MD4_Builtin_Test = skipUnless(TEST_MODE("full") or not has_native_md4,
"skipped under current test mode")(MD4_Builtin_Test)
-#=========================================================
+#=============================================================================
# test PBKDF1 support
-#=========================================================
+#=============================================================================
class Pbkdf1_Test(TestCase):
"test kdf helpers"
descriptionPrefix = "pbkdf1"
@@ -398,9 +398,9 @@ class Pbkdf1_Test(TestCase):
self.assertRaises(ValueError, helper, keylen=17, hash='md5')
self.assertRaises(TypeError, helper, keylen='1')
-#=========================================================
+#=============================================================================
# test PBKDF2 support
-#=========================================================
+#=============================================================================
class _Pbkdf2_Test(TestCase):
"test pbkdf2() support"
_disable_m2crypto = False
@@ -425,43 +425,43 @@ class _Pbkdf2_Test(TestCase):
# from rfc 3962
#
- #test case 1 / 128 bit
+ # test case 1 / 128 bit
(
hb("cdedb5281bb2f801565a1122b2563515"),
b("password"), b("ATHENA.MIT.EDUraeburn"), 1, 16
),
- #test case 2 / 128 bit
+ # test case 2 / 128 bit
(
hb("01dbee7f4a9e243e988b62c73cda935d"),
b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 16
),
- #test case 2 / 256 bit
+ # test case 2 / 256 bit
(
hb("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"),
b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 32
),
- #test case 3 / 256 bit
+ # test case 3 / 256 bit
(
hb("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"),
b("password"), b("ATHENA.MIT.EDUraeburn"), 1200, 32
),
- #test case 4 / 256 bit
+ # test case 4 / 256 bit
(
hb("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"),
b("password"), b('\x12\x34\x56\x78\x78\x56\x34\x12'), 5, 32
),
- #test case 5 / 256 bit
+ # test case 5 / 256 bit
(
hb("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"),
b("X"*64), b("pass phrase equals block size"), 1200, 32
),
- #test case 6 / 256 bit
+ # test case 6 / 256 bit
(
hb("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"),
b("X"*65), b("pass phrase exceeds block size"), 1200, 32
@@ -485,7 +485,7 @@ class _Pbkdf2_Test(TestCase):
b("password"), b("salt"), 4096, 20,
),
- #just runs too long - could enable if ALL option is set
+ # just runs too long - could enable if ALL option is set
##(
##
## unhexlify("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"),
@@ -548,7 +548,7 @@ class _Pbkdf2_Test(TestCase):
return pbkdf2(secret, salt, rounds, keylen, prf)
helper()
- #invalid rounds
+ # invalid rounds
self.assertRaises(ValueError, helper, rounds=0)
self.assertRaises(TypeError, helper, rounds='x')
@@ -594,6 +594,6 @@ class Pbkdf2_Builtin_Test(_Pbkdf2_Test):
Pbkdf2_Builtin_Test = skipUnless(TEST_MODE("full") or not M2Crypto,
"skipped under current test mode")(Pbkdf2_Builtin_Test)
-#=========================================================
-# EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py
index 8994651..6e4bfee 100644
--- a/passlib/tests/test_utils_handlers.py
+++ b/passlib/tests/test_utils_handlers.py
@@ -1,15 +1,15 @@
"""tests for passlib.pwhash -- (c) Assurance Technologies 2003-2009"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import re
import hashlib
from logging import getLogger
import warnings
-#site
-#pkg
+# site
+# pkg
from passlib.hash import ldap_md5, sha256_crypt
from passlib.registry import _unload_handler_name as unload_handler_name, \
register_crypt_handler, get_crypt_handler
@@ -20,12 +20,12 @@ from passlib.utils.compat import b, bytes, bascii_to_str, str_to_uascii, \
import passlib.utils.handlers as uh
from passlib.tests.utils import HandlerCase, TestCase, catch_warnings
from passlib.utils.compat import u, PY3
-#module
+# module
log = getLogger(__name__)
-#=========================================================
+#=============================================================================
# utils
-#=========================================================
+#=============================================================================
def _makelang(alphabet, size):
"generate all strings of given size using alphabet"
def helper(size):
@@ -38,15 +38,15 @@ def _makelang(alphabet, size):
yield char+tail
return set(helper(size))
-#=========================================================
-#test GenericHandler & associates mixin classes
-#=========================================================
+#=============================================================================
+# test GenericHandler & associates mixin classes
+#=============================================================================
class SkeletonTest(TestCase):
"test hash support classes"
- #=========================================================
+ #===================================================================
# StaticHandler
- #=========================================================
+ #===================================================================
def test_00_static_handler(self):
"test StaticHandler class"
@@ -140,9 +140,9 @@ class SkeletonTest(TestCase):
del d1.genhash
self.assertRaises(NotImplementedError, d1.encrypt, 'test')
- #=========================================================
- #GenericHandler & mixins
- #=========================================================
+ #===================================================================
+ # GenericHandler & mixins
+ #===================================================================
def test_10_identify(self):
"test GenericHandler.identify()"
class d1(uh.GenericHandler):
@@ -282,7 +282,7 @@ class SkeletonTest(TestCase):
self.assertEqual(norm_salt(salt='aaaabb', relaxed=True), 'aaaa')
self.consumeWarningList(wlog, PasslibHashWarning)
- #check generated salts
+ # check generated salts
with catch_warnings(record=True) as wlog:
# check too-small salt size
@@ -375,39 +375,39 @@ class SkeletonTest(TestCase):
def _calc_checksum_b(self, secret):
return 'b'
- #test no backends
+ # test no backends
self.assertRaises(MissingBackendError, d1.get_backend)
self.assertRaises(MissingBackendError, d1.set_backend)
self.assertRaises(MissingBackendError, d1.set_backend, 'any')
self.assertRaises(MissingBackendError, d1.set_backend, 'default')
self.assertFalse(d1.has_backend())
- #enable 'b' backend
+ # enable 'b' backend
d1._has_backend_b = True
- #test lazy load
+ # test lazy load
obj = d1()
self.assertEqual(obj._calc_checksum('s'), 'b')
- #test repeat load
+ # test repeat load
d1.set_backend('b')
d1.set_backend('any')
self.assertEqual(obj._calc_checksum('s'), 'b')
- #test unavailable
+ # test unavailable
self.assertRaises(MissingBackendError, d1.set_backend, 'a')
self.assertTrue(d1.has_backend('b'))
self.assertFalse(d1.has_backend('a'))
- #enable 'a' backend also
+ # enable 'a' backend also
d1._has_backend_a = True
- #test explicit
+ # test explicit
self.assertTrue(d1.has_backend())
d1.set_backend('a')
self.assertEqual(obj._calc_checksum('s'), 'a')
- #test unknown backend
+ # test unknown backend
self.assertRaises(ValueError, d1.set_backend, 'c')
self.assertRaises(ValueError, d1.has_backend, 'c')
@@ -453,10 +453,10 @@ class SkeletonTest(TestCase):
d1.default_ident = None
self.assertRaises(AssertionError, norm_ident, use_defaults=True)
- #=========================================================
+ #===================================================================
# experimental - the following methods are not finished or tested,
# but way work correctly for some hashes
- #=========================================================
+ #===================================================================
def test_91_parsehash(self):
"test parsehash()"
# NOTE: this just tests some existing GenericHandler classes
@@ -538,13 +538,13 @@ class SkeletonTest(TestCase):
##self.assertEqual(hash.fshp.bitsize(variant=1),
## {'checksum': 256, 'rounds': 13, 'salt': 128})
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#PrefixWrapper
-#=========================================================
+#=============================================================================
+# PrefixWrapper
+#=============================================================================
class dummy_handler_in_registry(object):
"context manager that inserts dummy handler in registry"
def __init__(self, name):
@@ -572,15 +572,15 @@ class PrefixWrapperTest(TestCase):
"test PrefixWrapper lazy loading of handler"
d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}", lazy=True)
- #check base state
+ # check base state
self.assertEqual(d1._wrapped_name, "ldap_md5")
self.assertIs(d1._wrapped_handler, None)
- #check loading works
+ # check loading works
self.assertIs(d1.wrapped, ldap_md5)
self.assertIs(d1._wrapped_handler, ldap_md5)
- #replace w/ wrong handler, make sure doesn't reload w/ dummy
+ # replace w/ wrong handler, make sure doesn't reload w/ dummy
with dummy_handler_in_registry("ldap_md5") as dummy:
self.assertIs(d1.wrapped, ldap_md5)
@@ -588,12 +588,12 @@ class PrefixWrapperTest(TestCase):
"test PrefixWrapper active loading of handler"
d1 = uh.PrefixWrapper("d1", "ldap_md5", "{XXX}", "{MD5}")
- #check base state
+ # check base state
self.assertEqual(d1._wrapped_name, "ldap_md5")
self.assertIs(d1._wrapped_handler, ldap_md5)
self.assertIs(d1.wrapped, ldap_md5)
- #replace w/ wrong handler, make sure doesn't reload w/ dummy
+ # replace w/ wrong handler, make sure doesn't reload w/ dummy
with dummy_handler_in_registry("ldap_md5") as dummy:
self.assertIs(d1.wrapped, ldap_md5)
@@ -602,12 +602,12 @@ class PrefixWrapperTest(TestCase):
d1 = uh.PrefixWrapper("d1", ldap_md5, "{XXX}", "{MD5}")
- #check base state
+ # check base state
self.assertEqual(d1._wrapped_name, None)
self.assertIs(d1._wrapped_handler, ldap_md5)
self.assertIs(d1.wrapped, ldap_md5)
- #replace w/ wrong handler, make sure doesn't reload w/ dummy
+ # replace w/ wrong handler, make sure doesn't reload w/ dummy
with dummy_handler_in_registry("ldap_md5") as dummy:
self.assertIs(d1.wrapped, ldap_md5)
@@ -629,22 +629,22 @@ class PrefixWrapperTest(TestCase):
dph = "{XXX}X03MO1qnZdYdgyfeuILPmQ=="
lph = "{MD5}X03MO1qnZdYdgyfeuILPmQ=="
- #genconfig
+ # genconfig
self.assertIs(d1.genconfig(), None)
- #genhash
+ # genhash
self.assertEqual(d1.genhash("password", None), dph)
self.assertEqual(d1.genhash("password", dph), dph)
self.assertRaises(ValueError, d1.genhash, "password", lph)
- #encrypt
+ # encrypt
self.assertEqual(d1.encrypt("password"), dph)
- #identify
+ # identify
self.assertTrue(d1.identify(dph))
self.assertFalse(d1.identify(lph))
- #verify
+ # verify
self.assertRaises(ValueError, d1.verify, "password", lph)
self.assertTrue(d1.verify("password", dph))
@@ -713,11 +713,11 @@ class PrefixWrapperTest(TestCase):
h = uh.PrefixWrapper("h2", "md5_crypt", orig_prefix="$6$")
self.assertRaises(ValueError, h.encrypt, 'test')
-#=========================================================
-#sample algorithms - these serve as known quantities
+#=============================================================================
+# sample algorithms - these serve as known quantities
# to test the unittests themselves, as well as other
# parts of passlib. they shouldn't be used as actual password schemes.
-#=========================================================
+#=============================================================================
class UnsaltedHash(uh.StaticHandler):
"test algorithm which lacks a salt"
name = "unsalted_test_hash"
@@ -762,12 +762,12 @@ class SaltedHash(uh.HasSalt, uh.GenericHandler):
data = self.salt.encode("ascii") + secret + self.salt.encode("ascii")
return str_to_uascii(hashlib.sha1(data).hexdigest())
-#=========================================================
-#test sample algorithms - really a self-test of HandlerCase
-#=========================================================
+#=============================================================================
+# test sample algorithms - really a self-test of HandlerCase
+#=============================================================================
-#TODO: provide data samples for algorithms
-# (positive knowns, negative knowns, invalid identify)
+# TODO: provide data samples for algorithms
+# (positive knowns, negative knowns, invalid identify)
UPASS_TEMP = u('\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2')
@@ -801,6 +801,6 @@ class SaltedHashTest(HandlerCase):
self.assertRaises(ValueError, SaltedHash,
checksum=SaltedHash._stub_checksum, salt='xxx')
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/test_win32.py b/passlib/tests/test_win32.py
index 7fd475a..9b01752 100644
--- a/passlib/tests/test_win32.py
+++ b/passlib/tests/test_win32.py
@@ -1,19 +1,19 @@
"""tests for passlib.win32 -- (c) Assurance Technologies 2003-2009"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify
import warnings
-#site
-#pkg
+# site
+# pkg
from passlib.tests.utils import TestCase
-#module
+# module
from passlib.utils.compat import u
-#=========================================================
+#=============================================================================
#
-#=========================================================
+#=============================================================================
class UtilTest(TestCase):
"test util funcs in passlib.win32"
@@ -46,6 +46,6 @@ class UtilTest(TestCase):
result = raw_nthash(secret, hex=True)
self.assertEqual(result, hash)
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index ffce80a..6257acb 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -1,9 +1,9 @@
"""helpers for passlib unittests"""
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
from __future__ import with_statement
-#core
+# core
import logging; log = logging.getLogger(__name__)
import re
import os
@@ -14,8 +14,8 @@ from passlib.exc import PasslibHashWarning
from passlib.utils.compat import PY27, PY_MIN_32, PY3, JYTHON
import warnings
from warnings import warn
-#site
-#pkg
+# site
+# pkg
from passlib.exc import MissingBackendError
import passlib.registry as registry
from passlib.tests.backports import TestCase as _TestCase, catch_warnings, skip, skipIf, skipUnless
@@ -25,20 +25,20 @@ from passlib.utils import has_rounds_info, has_salt_info, rounds_cost_values, \
from passlib.utils.compat import b, bytes, iteritems, irange, callable, \
base_string_types, exc_err, u, unicode, PY2
import passlib.utils.handlers as uh
-#local
+# local
__all__ = [
- #util funcs
+ # util funcs
'TEST_MODE',
'set_file', 'get_file',
- #unit testing
+ # unit testing
'TestCase',
'HandlerCase',
]
-#=========================================================
+#=============================================================================
# environment detection
-#=========================================================
+#=============================================================================
# figure out if we're running under GAE;
# some tests (e.g. FS writing) should be skipped.
# XXX: is there better way to do this?
@@ -67,9 +67,9 @@ def _get_timer_resolution(timer):
return min(sample() for _ in range(3))
TICK_RESOLUTION = _get_timer_resolution(tick)
-#=========================================================
+#=============================================================================
# test mode
-#=========================================================
+#=============================================================================
_TEST_MODES = ["quick", "default", "full"]
_test_mode = _TEST_MODES.index(os.environ.get("PASSLIB_TEST_MODE",
"default").strip().lower())
@@ -99,9 +99,9 @@ def TEST_MODE(min=None, max=None):
return False
return True
-#=========================================================
+#=============================================================================
# hash object inspection
-#=========================================================
+#=============================================================================
def has_crypt_support(handler):
"check if host's crypt() supports this natively"
if hasattr(handler, "orig_prefix"):
@@ -156,9 +156,9 @@ class temporary_backend(object):
def __exit__(self, *exc_info):
self.handler.set_backend(self._orig)
-#=========================================================
+#=============================================================================
# misc helpers
-#=========================================================
+#=============================================================================
def set_file(path, content):
"set file to specified bytes"
if isinstance(content, unicode):
@@ -200,9 +200,9 @@ def quicksleep(delay):
while tick()-start < delay:
pass
-#=========================================================
+#=============================================================================
# custom test harness
-#=========================================================
+#=============================================================================
class TestCase(_TestCase):
"""passlib-specific test case class
@@ -213,13 +213,13 @@ class TestCase(_TestCase):
* __msg__ kwd added to assertRaises()
* suite of methods for matching against warnings
"""
- #====================================================================
+ #===================================================================
# add various custom features
- #====================================================================
+ #===================================================================
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# make it easy for test cases to add common prefix to shortDescription
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# string prepended to all tests in TestCase
descriptionPrefix = None
@@ -232,10 +232,10 @@ class TestCase(_TestCase):
desc = "%s: %s" % (prefix, desc or str(self))
return desc
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# hack things so nose and ut2 both skip subclasses who have
# "__unittest_skip=True" set, or whose names start with "_"
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
@classproperty
def __unittest_skip__(cls):
# NOTE: this attr is technically a unittest2 internal detail.
@@ -254,9 +254,9 @@ class TestCase(_TestCase):
# flag to skip *this* class
__unittest_skip = True
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# reset warning filters & registry before each test
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# flag to reset all warning filters & ignore state
resetWarningState = True
@@ -272,10 +272,10 @@ class TestCase(_TestCase):
ctx.__enter__()
self.addCleanup(ctx.__exit__)
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# tweak message formatting so longMessage mode is only enabled
# if msg ends with ":", and turn on longMessage by default.
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
longMessage = True
def _formatMessage(self, msg, std):
@@ -284,9 +284,9 @@ class TestCase(_TestCase):
else:
return msg or std
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# override assertRaises() to support '__msg__' keyword
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
def assertRaises(self, _exc_type, _callable=None, *args, **kwds):
msg = kwds.pop("__msg__", None)
if _callable is None:
@@ -301,16 +301,16 @@ class TestCase(_TestCase):
_exc_type)
raise self.failureException(self._formatMessage(msg, std))
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
# forbid a bunch of deprecated aliases so I stop using them
- #----------------------------------------------------------------
+ #---------------------------------------------------------------
def assertEquals(self, *a, **k):
raise AssertionError("this alias is deprecated by unittest2")
assertNotEquals = assertRegexMatches = assertEquals
- #============================================================
+ #===================================================================
# custom methods for matching warnings
- #============================================================
+ #===================================================================
def assertWarning(self, warning,
message_re=None, message=None,
category=None,
@@ -425,9 +425,9 @@ class TestCase(_TestCase):
def _formatWarningList(self, wlist):
return "[%s]" % ", ".join(self._formatWarning(entry) for entry in wlist)
- #============================================================
+ #===================================================================
# capability tests
- #============================================================
+ #===================================================================
def require_stringprep(self):
"helper to skip test if stringprep is missing"
from passlib.utils import stringprep
@@ -446,9 +446,9 @@ class TestCase(_TestCase):
if GAE:
return self.skipTest("GAE doesn't offer read/write filesystem access")
- #============================================================
+ #===================================================================
# other
- #============================================================
+ #===================================================================
_mktemp_queue = None
def mktemp(self, *args, **kwds):
@@ -468,13 +468,13 @@ class TestCase(_TestCase):
queue.append(path)
return path
- #============================================================
- #eoc
- #============================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#=========================================================
-#other unittest helpers
-#=========================================================
+#=============================================================================
+# other unittest helpers
+#=============================================================================
RESERVED_BACKEND_NAMES = ["any", "default"]
class HandlerCase(TestCase):
@@ -494,13 +494,13 @@ class HandlerCase(TestCase):
This is subclass of :class:`unittest.TestCase`
(or :class:`unittest2.TestCase` if available).
"""
- #=========================================================
+ #===================================================================
# class attrs - should be filled in by subclass
- #=========================================================
+ #===================================================================
- #--------------------------------------------------
+ #---------------------------------------------------------------
# handler setup
- #--------------------------------------------------
+ #---------------------------------------------------------------
# handler class to test [required]
handler = None
@@ -508,9 +508,9 @@ class HandlerCase(TestCase):
# if set, run tests against specified backend
backend = None
- #--------------------------------------------------
+ #---------------------------------------------------------------
# test vectors
- #--------------------------------------------------
+ #---------------------------------------------------------------
# list of (secret, hash) tuples which are known to be correct
known_correct_hashes = []
@@ -549,9 +549,9 @@ class HandlerCase(TestCase):
b('\xe2\x82\xac\xc2\xa5$')
]
- #--------------------------------------------------
+ #---------------------------------------------------------------
# option flags
- #--------------------------------------------------
+ #---------------------------------------------------------------
# maximum number of chars which hash will include in digest.
# ``None`` (the default) indicates the hash uses ALL of the password.
@@ -580,9 +580,9 @@ class HandlerCase(TestCase):
return b("\x00")
return None
- #=========================================================
+ #===================================================================
# internal class attrs
- #=========================================================
+ #===================================================================
__unittest_skip = True
@property
@@ -593,19 +593,19 @@ class HandlerCase(TestCase):
name += " (%s backend)" % (handler.get_backend(),)
return name
- #=========================================================
+ #===================================================================
# internal instance attrs
- #=========================================================
+ #===================================================================
# indicates safe_crypt() has been patched to use another backend of handler.
using_patched_crypt = False
- #=========================================================
+ #===================================================================
# support methods
- #=========================================================
+ #===================================================================
- #------------------------------------------------------
+ #---------------------------------------------------------------
# configuration helpers
- #------------------------------------------------------
+ #---------------------------------------------------------------
@property
def supports_config_string(self):
return self.do_genconfig() is not None
@@ -625,9 +625,9 @@ class HandlerCase(TestCase):
known = list(self.iter_known_hashes())
return rng.choice(known)
- #------------------------------------------------------
+ #---------------------------------------------------------------
# test helpers
- #------------------------------------------------------
+ #---------------------------------------------------------------
def check_verify(self, secret, hash, msg=None, negate=False):
"helper to check verify() outcome, honoring is_disabled_handler"
result = self.do_verify(secret, hash)
@@ -651,10 +651,10 @@ class HandlerCase(TestCase):
self.assertIsInstance(result, str,
"%s() failed to return native string: %r" % (func_name, result,))
- #------------------------------------------------------
+ #---------------------------------------------------------------
# PasswordHash helpers - wraps all calls to PasswordHash api,
# so that subclasses can fill in defaults and account for other specialized behavior
- #------------------------------------------------------
+ #---------------------------------------------------------------
def populate_settings(self, kwds):
"subclassable method to populate default settings"
# use lower rounds settings for certain test modes
@@ -703,10 +703,10 @@ class HandlerCase(TestCase):
secret = self.populate_context(secret, kwds)
return self.handler.genhash(secret, config, **kwds)
- #------------------------------------------------------
+ #---------------------------------------------------------------
# automatically generate subclasses for testing specific backends,
# and other backend helpers
- #------------------------------------------------------
+ #---------------------------------------------------------------
@classmethod
def _enable_backend_case(cls, backend):
"helper for create_backend_cases(); returns reason to skip backend, or None"
@@ -721,8 +721,8 @@ class HandlerCase(TestCase):
from passlib.utils import has_crypt
if backend == "os_crypt" and has_crypt:
if TEST_MODE("full") and cls.find_crypt_replacement():
- #in this case, HandlerCase will monkeypatch os_crypt
- #to use another backend, just so we can test os_crypt fully.
+ # in this case, HandlerCase will monkeypatch os_crypt
+ # to use another backend, just so we can test os_crypt fully.
return None
else:
return "hash not supported by os crypt()"
@@ -761,9 +761,9 @@ class HandlerCase(TestCase):
return name
return None
- #=========================================================
+ #===================================================================
# setup
- #=========================================================
+ #===================================================================
def setUp(self):
super(HandlerCase, self).setUp()
@@ -776,9 +776,9 @@ class HandlerCase(TestCase):
self.addCleanup(handler.set_backend, handler.get_backend())
handler.set_backend(backend)
- #=========================================================
+ #===================================================================
# basic tests
- #=========================================================
+ #===================================================================
def test_01_required_attributes(self):
"validate required attributes"
handler = self.handler
@@ -969,9 +969,9 @@ class HandlerCase(TestCase):
raise TypeError("has_backend(%r) returned invalid "
"value: %r" % (backend, ret))
- #==============================================================
+ #===================================================================
# salts
- #==============================================================
+ #===================================================================
def require_salt(self):
if 'salt' not in self.handler.setting_kwds:
raise self.skipTest("handler doesn't have salt")
@@ -988,24 +988,24 @@ class HandlerCase(TestCase):
AssertionError = self.failureException
cls = self.handler
- #check max_salt_size
+ # check max_salt_size
mx_set = (cls.max_salt_size is not None)
if mx_set and cls.max_salt_size < 1:
raise AssertionError("max_salt_chars must be >= 1")
- #check min_salt_size
+ # check min_salt_size
if cls.min_salt_size < 0:
raise AssertionError("min_salt_chars must be >= 0")
if mx_set and cls.min_salt_size > cls.max_salt_size:
raise AssertionError("min_salt_chars must be <= max_salt_chars")
- #check default_salt_size
+ # check default_salt_size
if cls.default_salt_size < cls.min_salt_size:
raise AssertionError("default_salt_size must be >= min_salt_size")
if mx_set and cls.default_salt_size > cls.max_salt_size:
raise AssertionError("default_salt_size must be <= max_salt_size")
- #check for 'salt_size' keyword
+ # check for 'salt_size' keyword
if 'salt_size' not in cls.setting_kwds and \
(not mx_set or cls.min_salt_size < cls.max_salt_size):
# NOTE: only bothering to issue warning if default_salt_size
@@ -1014,7 +1014,7 @@ class HandlerCase(TestCase):
warn("%s: hash handler supports range of salt sizes, "
"but doesn't offer 'salt_size' setting" % (cls.name,))
- #check salt_chars & default_salt_chars
+ # check salt_chars & default_salt_chars
if cls.salt_chars:
if not cls.default_salt_chars:
raise AssertionError("default_salt_chars must not be empty")
@@ -1200,9 +1200,9 @@ class HandlerCase(TestCase):
if not (salt_type is bytes or (PY2 and salt_type is unicode)):
self.assertRaises(TypeError, self.do_encrypt, 'stub', salt=b('x'))
- #==============================================================
+ #===================================================================
# rounds
- #==============================================================
+ #===================================================================
def require_rounds_info(self):
if not has_rounds_info(self.handler):
raise self.skipTest("handler lacks rounds attributes")
@@ -1214,26 +1214,26 @@ class HandlerCase(TestCase):
cls = self.handler
AssertionError = self.failureException
- #check max_rounds
+ # check max_rounds
if cls.max_rounds is None:
raise AssertionError("max_rounds not specified")
if cls.max_rounds < 1:
raise AssertionError("max_rounds must be >= 1")
- #check min_rounds
+ # check min_rounds
if cls.min_rounds < 0:
raise AssertionError("min_rounds must be >= 0")
if cls.min_rounds > cls.max_rounds:
raise AssertionError("min_rounds must be <= max_rounds")
- #check default_rounds
+ # check default_rounds
if cls.default_rounds is not None:
if cls.default_rounds < cls.min_rounds:
raise AssertionError("default_rounds must be >= min_rounds")
if cls.default_rounds > cls.max_rounds:
raise AssertionError("default_rounds must be <= max_rounds")
- #check rounds_cost
+ # check rounds_cost
if cls.rounds_cost not in rounds_cost_values:
raise AssertionError("unknown rounds cost constant: %r" % (cls.rounds_cost,))
@@ -1271,9 +1271,9 @@ class HandlerCase(TestCase):
# TODO: check relaxed mode clips max+1
- #==============================================================
+ #===================================================================
# idents
- #==============================================================
+ #===================================================================
def test_30_HasManyIdents(self):
"validate HasManyIdents configuration"
cls = self.handler
@@ -1300,7 +1300,7 @@ class HandlerCase(TestCase):
if cls.ident_aliases:
for alias, ident in iteritems(cls.ident_aliases):
self.assertIsInstance(alias, unicode,
- "cls.ident_aliases keys must be unicode:") #XXX: allow ints?
+ "cls.ident_aliases keys must be unicode:") # XXX: allow ints?
self.assertIsInstance(ident, unicode,
"cls.ident_aliases values must be unicode:")
self.assertTrue(ident in cls.ident_values,
@@ -1326,9 +1326,9 @@ class HandlerCase(TestCase):
# TODO: check various supported idents
- #==============================================================
+ #===================================================================
# passwords
- #==============================================================
+ #===================================================================
def test_60_secret_size(self):
"test password size limits"
sc = self.secret_size
@@ -1428,9 +1428,9 @@ class HandlerCase(TestCase):
for c in chars:
self.assertRaises(ValueError, self.do_encrypt, base + c + base)
- #==============================================================
+ #===================================================================
# check identify(), verify(), genhash() against test vectors
- #==============================================================
+ #===================================================================
def is_secret_8bit(self, secret):
secret = self.populate_context(secret, {})
return not is_ascii_safe(secret)
@@ -1652,9 +1652,9 @@ class HandlerCase(TestCase):
self.do_identify('\xe2\x82\xac\xc2\xa5$') # utf-8
self.do_identify('abc\x91\x00') # non-utf8
- #=========================================================
+ #===================================================================
# fuzz testing
- #=========================================================
+ #===================================================================
"""the following attempts to perform some basic fuzz testing
of the handler, based on whatever information can be found about it.
it does as much as it can within a fixed amount of time
@@ -1879,13 +1879,13 @@ class HandlerCase(TestCase):
return None
return ident
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=================================================================
+#=============================================================================
# HandlerCase mixins providing additional tests for certain hashes
-#=================================================================
+#=============================================================================
class OsCryptMixin(HandlerCase):
"""helper used by create_backend_case() which adds additional features
to test the os_crypt backend.
@@ -1898,16 +1898,16 @@ class OsCryptMixin(HandlerCase):
* check that native crypt support is detected correctly for known platforms.
"""
- #=========================================================
+ #===================================================================
# option flags
- #=========================================================
+ #===================================================================
# platforms that are known to support / not support this hash natively.
# list of (platform_regex, True|False|None) entries.
platform_crypt_support = []
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
__unittest_skip = True
# force this backend
@@ -1916,9 +1916,9 @@ class OsCryptMixin(HandlerCase):
# flag read by HandlerCase to detect if fake os crypt is enabled.
using_patched_crypt = False
- #=========================================================
+ #===================================================================
# setup
- #=========================================================
+ #===================================================================
def setUp(self):
assert self.backend == "os_crypt"
if not self.handler.has_backend("os_crypt"):
@@ -1949,9 +1949,9 @@ class OsCryptMixin(HandlerCase):
mod._crypt = crypt_stub
self.using_patched_crypt = True
- #=========================================================
+ #===================================================================
# custom tests
- #=========================================================
+ #===================================================================
def _use_mock_crypt(self):
"patch safe_crypt() so it returns mock value"
import passlib.utils as mod
@@ -2017,7 +2017,7 @@ class OsCryptMixin(HandlerCase):
# e.g. platform='freebsd8' ... sha256_crypt not added until 8.3
raise self.skipTest("varied support on %r platform" % platform)
elif state != self.using_patched_crypt:
- return
+ return
elif state:
self.fail("expected %r platform would have native support "
"for %r" % (platform, self.handler.name))
@@ -2025,9 +2025,9 @@ class OsCryptMixin(HandlerCase):
self.fail("did not expect %r platform would have native support "
"for %r" % (platform, self.handler.name))
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class UserHandlerMixin(HandlerCase):
"""helper for handlers w/ 'user' context kwd; mixin for HandlerCase
@@ -2037,21 +2037,21 @@ class UserHandlerMixin(HandlerCase):
calls. as well, passing in a pair of strings as the password
will be interpreted as (secret,user)
"""
- #=========================================================
+ #===================================================================
# option flags
- #=========================================================
+ #===================================================================
default_user = "user"
requires_user = True
user_case_insensitive = False
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
__unittest_skip = True
- #=========================================================
+ #===================================================================
# custom tests
- #=========================================================
+ #===================================================================
def test_80_user(self):
"test user context keyword"
handler = self.handler
@@ -2091,9 +2091,9 @@ class UserHandlerMixin(HandlerCase):
# TODO: user size? kinda dicey, depends on algorithm.
- #=========================================================
+ #===================================================================
# override test helpers
- #=========================================================
+ #===================================================================
def populate_context(self, secret, kwds):
"insert username into kwds"
if isinstance(secret, tuple):
@@ -2106,9 +2106,9 @@ class UserHandlerMixin(HandlerCase):
kwds['user'] = user
return secret
- #=========================================================
+ #===================================================================
# modify fuzz testing
- #=========================================================
+ #===================================================================
fuzz_user_alphabet = u("asdQWE123")
fuzz_settings = HandlerCase.fuzz_settings + ["user"]
@@ -2118,9 +2118,9 @@ class UserHandlerMixin(HandlerCase):
return None
return getrandstr(rng, self.fuzz_user_alphabet, rng.randint(2,10))
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class EncodingHandlerMixin(HandlerCase):
"""helper for handlers w/ 'encoding' context kwd; mixin for HandlerCase
@@ -2130,9 +2130,9 @@ class EncodingHandlerMixin(HandlerCase):
calls by passing in a pair of strings as the password
will be interpreted as (secret,encoding)
"""
- #=========================================================
+ #===================================================================
# instance attrs
- #=========================================================
+ #===================================================================
__unittest_skip = True
# restrict stock passwords & fuzz alphabet to latin-1,
@@ -2151,9 +2151,9 @@ class EncodingHandlerMixin(HandlerCase):
secret, encoding = secret
kwds.setdefault('encoding', encoding)
return secret
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
#=============================================================================
# warnings helpers
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index 3e503a2..c0f9a47 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -1,9 +1,9 @@
"""passlib.utils -- helpers for writing password hashes"""
#=============================================================================
-#imports
+# imports
#=============================================================================
from passlib.utils.compat import PYPY, JYTHON
-#core
+# core
from base64 import b64encode, b64decode
from codecs import lookup as _lookup_codec
from functools import update_wrapper
@@ -26,13 +26,13 @@ import time
if stringprep:
import unicodedata
from warnings import warn
-#site
-#pkg
+# site
+# pkg
from passlib.exc import ExpectedStringError
from passlib.utils.compat import add_doc, b, bytes, join_bytes, join_byte_values, \
join_byte_elems, exc_err, irange, imap, PY3, u, \
join_unicode, unicode, byte_elem_value, PY_MIN_32, next_method_attr
-#local
+# local
__all__ = [
# constants
'PYPY',
@@ -86,9 +86,9 @@ __all__ = [
'has_salt_info',
]
-#=================================================================================
+#=============================================================================
# constants
-#=================================================================================
+#=============================================================================
# bitsize of system architecture (32 or 64)
sys_bits = int(math.log(sys.maxsize if PY3 else sys.maxint, 2) + 1.5)
@@ -116,9 +116,9 @@ _USPACE = u(" ")
# maximum password size which passlib will allow; see exc.PasswordSizeError
MAX_PASSWORD_SIZE = int(os.environ.get("PASSLIB_MAX_PASSWORD_SIZE") or 4096)
-#=================================================================================
-#decorators and meta helpers
-#=================================================================================
+#=============================================================================
+# decorators and meta helpers
+#=============================================================================
class classproperty(object):
"""Function decorator which acts like a combination of classmethod+property (limited to read-only properties)"""
@@ -221,7 +221,7 @@ class memoized_property(object):
"py3 alias"
return self.im_func
-#works but not used
+# works but not used
##class memoized_class_property(object):
## """function decorator which calls function as classmethod,
## and replaces itself with result for current and all future invocations.
@@ -638,9 +638,9 @@ def to_hash_str(source, encoding="ascii"): # pragma: no cover -- deprecated & un
"deprecated, use to_native_str() instead"
return to_native_str(source, encoding, param="hash")
-#=================================================================================
+#=============================================================================
# base64-variant encoding
-#=================================================================================
+#=============================================================================
class Base64Engine(object):
"""Provides routines for encoding/decoding base64 data using
@@ -707,9 +707,9 @@ class Base64Engine(object):
boolean flag indicating this using big-endian encoding.
"""
- #=============================================================
+ #===================================================================
# instance attrs
- #=============================================================
+ #===================================================================
# public config
bytemap = None # charmap as bytes
big = None # little or big endian
@@ -723,9 +723,9 @@ class Base64Engine(object):
_encode_bytes = None # throws IndexError if bad value (shouldn't happen)
_decode_bytes = None # throws KeyError if bad char.
- #=============================================================
+ #===================================================================
# init
- #=============================================================
+ #===================================================================
def __init__(self, charmap, big=False):
# validate charmap, generate encode64/decode64 helper functions.
if isinstance(charmap, unicode):
@@ -765,9 +765,9 @@ class Base64Engine(object):
"charmap as unicode"
return self.bytemap.decode("latin-1")
- #=============================================================
+ #===================================================================
# encoding byte strings
- #=============================================================
+ #===================================================================
def encode_bytes(self, source):
"""encode bytes to base64 string.
@@ -867,9 +867,9 @@ class Base64Engine(object):
yield ((v1&0x03)<<4)|(v2>>4)
yield ((v2&0x0f)<<2)
- #=============================================================
+ #===================================================================
# decoding byte strings
- #=============================================================
+ #===================================================================
def decode_bytes(self, source):
"""decode bytes from base64 string.
@@ -885,7 +885,7 @@ class Base64Engine(object):
## source = source.rstrip(padding)
chunks, tail = divmod(len(source), 4)
if tail == 1:
- #only 6 bits left, can't encode a whole byte!
+ # only 6 bits left, can't encode a whole byte!
raise ValueError("input string length cannot be == 1 mod 4")
next_value = getattr(imap(self._decode64, source), next_method_attr)
try:
@@ -923,9 +923,9 @@ class Base64Engine(object):
v1 = next_value()
v2 = next_value()
yield v1 | ((v2 & 0x3) << 6)
- #NOTE: if tail == 2, 4 msb of v2 are ignored (should be 0)
+ # NOTE: if tail == 2, 4 msb of v2 are ignored (should be 0)
if tail == 3:
- #NOTE: 2 msb of v3 are ignored (should be 0)
+ # NOTE: 2 msb of v3 are ignored (should be 0)
v3 = next_value()
yield (v2>>2) | ((v3 & 0xF) << 4)
@@ -958,15 +958,15 @@ class Base64Engine(object):
v1 = next_value()
v2 = next_value()
yield (v1<<2) | (v2>>4)
- #NOTE: if tail == 2, 4 lsb of v2 are ignored (should be 0)
+ # NOTE: if tail == 2, 4 lsb of v2 are ignored (should be 0)
if tail == 3:
- #NOTE: 2 lsb of v3 are ignored (should be 0)
+ # NOTE: 2 lsb of v3 are ignored (should be 0)
v3 = next_value()
yield ((v2&0xF)<<4) | (v3>>2)
- #=============================================================
+ #===================================================================
# encode/decode helpers
- #=============================================================
+ #===================================================================
# padmap2/3 - dict mapping last char of string ->
# equivalent char with no padding bits set.
@@ -1047,9 +1047,9 @@ class Base64Engine(object):
## self.charmap if unicode else self.bytemap, size)
## return self.repair_unused(data)
- #=============================================================
+ #===================================================================
# transposed encoding/decoding
- #=============================================================
+ #===================================================================
def encode_transposed_bytes(self, source, offsets):
"encode byte string, first transposing source using offset list"
if not isinstance(source, bytes):
@@ -1068,9 +1068,9 @@ class Base64Engine(object):
buf[off] = char
return join_byte_elems(buf)
- #=============================================================
+ #===================================================================
# integer decoding helpers - mainly used by des_crypt family
- #=============================================================
+ #===================================================================
def _decode_int(self, source, bits):
"""decode base64 string -> integer
@@ -1107,9 +1107,9 @@ class Base64Engine(object):
out &= (1<<bits)-1
return out
- #---------------------------------------------
+ #---------------------------------------------------------------
# optimized versions for common integer sizes
- #---------------------------------------------
+ #---------------------------------------------------------------
def decode_int6(self, source):
"decode single character -> 6 bit integer"
@@ -1165,9 +1165,9 @@ class Base64Engine(object):
"""
return self._decode_int(source, 64)
- #=============================================================
+ #===================================================================
# integer encoding helpers - mainly used by des_crypt family
- #=============================================================
+ #===================================================================
def _encode_int(self, value, bits):
"""encode integer into base64 format
@@ -1190,9 +1190,9 @@ class Base64Engine(object):
return join_byte_elems(imap(self._encode64,
((value>>off) & 0x3f for off in itr)))
- #---------------------------------------------
+ #---------------------------------------------------------------
# optimized versions for common integer sizes
- #---------------------------------------------
+ #---------------------------------------------------------------
def encode_int6(self, value):
"encodes 6-bit integer -> single hash64 character"
@@ -1232,9 +1232,9 @@ class Base64Engine(object):
raise ValueError("value out of range")
return self._encode_int(value, 64)
- #=============================================================
+ #===================================================================
# eof
- #=============================================================
+ #===================================================================
class LazyBase64Engine(Base64Engine):
"Base64Engine which delays initialization until it's accessed"
@@ -1303,13 +1303,13 @@ def ab64_decode(data):
else: # off == 1
raise ValueError("invalid base64 input")
-#=================================================================================
+#=============================================================================
# host OS helpers
-#=================================================================================
+#=============================================================================
try:
from crypt import crypt as _crypt
-except ImportError: #pragma: no cover
+except ImportError: # pragma: no cover
has_crypt = False
def safe_crypt(secret, hash):
return None
@@ -1408,16 +1408,16 @@ else:
# On most other platforms the best timer is time.time()
from time import time as tick
-#=================================================================================
+#=============================================================================
# randomness
-#=================================================================================
+#=============================================================================
-#-----------------------------------------------------------------------
+#------------------------------------------------------------------------
# setup rng for generating salts
-#-----------------------------------------------------------------------
+#------------------------------------------------------------------------
-#NOTE:
-# generating salts (eg h64_gensalt, below) doesn't require cryptographically
+# NOTE:
+# generating salts (e.g. h64_gensalt, below) doesn't require cryptographically
# strong randomness. it just requires enough range of possible outputs
# that making a rainbow table is too costly.
# so python's builtin merseen twister prng is used, but seeded each time
@@ -1426,48 +1426,48 @@ else:
try:
os.urandom(1)
has_urandom = True
-except NotImplementedError: #pragma: no cover
+except NotImplementedError: # pragma: no cover
has_urandom = False
def genseed(value=None):
"generate prng seed value from system resources"
- #if value is rng, extract a bunch of bits from it's state
+ # if value is rng, extract a bunch of bits from it's state
from hashlib import sha256
if hasattr(value, "getrandbits"):
value = value.getrandbits(256)
text = u("%s %s %s %.15f %s") % (
value,
- #if user specified a seed value (eg current rng state), mix it in
+ # if user specified a seed value (e.g. current rng state), mix it in
os.getpid() if hasattr(os, "getpid") else None,
- #add current process id
- #NOTE: not available in some environments, eg GAE
+ # add current process id
+ # NOTE: not available in some environments, e.g. GAE
id(object()),
- #id of a freshly created object.
- #(at least 2 bytes of which should be hard to predict)
+ # id of a freshly created object.
+ # (at least 2 bytes of which should be hard to predict)
time.time(),
- #the current time, to whatever precision os uses
+ # the current time, to whatever precision os uses
os.urandom(16).decode("latin-1") if has_urandom else 0,
- #if urandom available, might as well mix some bytes in.
+ # if urandom available, might as well mix some bytes in.
)
- #hash it all up and return it as int/long
+ # hash it all up and return it as int/long
return int(sha256(text.encode("utf-8")).hexdigest(), 16)
if has_urandom:
rng = random.SystemRandom()
-else: #pragma: no cover
- #NOTE: to reseed - rng.seed(genseed(rng))
+else: # pragma: no cover
+ # NOTE: to reseed - rng.seed(genseed(rng))
rng = random.Random(genseed())
-#-----------------------------------------------------------------------
+#------------------------------------------------------------------------
# some rng helpers
-#-----------------------------------------------------------------------
+#------------------------------------------------------------------------
def getrandbytes(rng, count):
"""return byte-string containing *count* number of randomly generated bytes, using specified rng"""
- #NOTE: would be nice if this was present in stdlib Random class
+ # NOTE: would be nice if this was present in stdlib Random class
###just in case rng provides this...
##meth = getattr(rng, "getrandbytes", None)
@@ -1477,7 +1477,7 @@ def getrandbytes(rng, count):
if not count:
return _BEMPTY
def helper():
- #XXX: break into chunks for large number of bits?
+ # XXX: break into chunks for large number of bits?
value = rng.getrandbits(count<<3)
i = 0
while i < count:
@@ -1491,7 +1491,7 @@ def getrandstr(rng, charset, count):
# NOTE: tests determined this is 4x faster than rng.sample(),
# which is why that's not being used here.
- #check alphabet & count
+ # check alphabet & count
if count < 0:
raise ValueError("count must be >= 0")
letters = len(charset)
@@ -1500,9 +1500,9 @@ def getrandstr(rng, charset, count):
if letters == 1:
return charset * count
- #get random value, and write out to buffer
+ # get random value, and write out to buffer
def helper():
- #XXX: break into chunks for large number of letters?
+ # XXX: break into chunks for large number of letters?
value = rng.randrange(0, letters**count)
i = 0
while i < count:
@@ -1534,9 +1534,9 @@ def generate_password(size=10, charset=_52charset):
"""
return getrandstr(rng, charset, size)
-#==========================================================
+#=============================================================================
# object type / interface tests
-#==========================================================
+#=============================================================================
_handler_attrs = (
"name",
"setting_kwds", "context_kwds",
@@ -1562,7 +1562,7 @@ def is_crypt_context(obj):
##def has_many_backends(handler):
## "check if handler provides multiple baceknds"
-## #NOTE: should also provide get_backend(), .has_backend(), and .backends attr
+## # NOTE: should also provide get_backend(), .has_backend(), and .backends attr
## return hasattr(handler, "set_backend")
def has_rounds_info(handler):
@@ -1587,6 +1587,6 @@ def has_salt_info(handler):
## else:
## raise TypeError("handler.salt_chars must be None/unicode/bytes")
-#=================================================================================
+#=============================================================================
# eof
-#=================================================================================
+#=============================================================================
diff --git a/passlib/utils/_blowfish/__init__.py b/passlib/utils/_blowfish/__init__.py
index d3444b8..ef90ac0 100644
--- a/passlib/utils/_blowfish/__init__.py
+++ b/passlib/utils/_blowfish/__init__.py
@@ -47,25 +47,25 @@ released under the BSD license::
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from itertools import chain
import struct
-#pkg
+# pkg
from passlib.utils import bcrypt64, getrandbytes, rng
from passlib.utils.compat import b, bytes, BytesIO, unicode, u
from passlib.utils._blowfish.unrolled import BlowfishEngine
-#local
+# local
__all__ = [
'BlowfishEngine',
'raw_bcrypt',
]
-#=========================================================
+#=============================================================================
# bcrypt constants
-#=========================================================
+#=============================================================================
# bcrypt constant data "OrpheanBeholderScryDoubt" as 6 integers
BCRYPT_CDATA = [
@@ -76,26 +76,26 @@ BCRYPT_CDATA = [
# struct used to encode ciphertext as digest (last output byte discarded)
digest_struct = struct.Struct(">6I")
-#=========================================================
-#base bcrypt helper
+#=============================================================================
+# base bcrypt helper
#
-#interface designed only for use by passlib.handlers.bcrypt:BCrypt
-#probably not suitable for other purposes
-#=========================================================
+# interface designed only for use by passlib.handlers.bcrypt:BCrypt
+# probably not suitable for other purposes
+#=============================================================================
BNULL = b('\x00')
def raw_bcrypt(password, ident, salt, log_rounds):
"""perform central password hashing step in bcrypt scheme.
:param password: the password to hash
- :param ident: identifier w/ minor version (eg 2, 2a)
+ :param ident: identifier w/ minor version (e.g. 2, 2a)
:param salt: the binary salt to use (encoded in bcrypt-base64)
:param rounds: the log2 of the number of rounds (as int)
:returns: bcrypt-base64 encoded checksum
"""
- #===========================================================
+ #===================================================================
# parse inputs
- #===========================================================
+ #===================================================================
# parse ident
assert isinstance(ident, unicode)
@@ -131,15 +131,15 @@ def raw_bcrypt(password, ident, salt, log_rounds):
if log_rounds < 4 or log_rounds > 31:
raise ValueError("Bad number of rounds")
- #===========================================================
+ #===================================================================
#
# run EKS-Blowfish algorithm
#
# This uses the "enhanced key schedule" step described by
# Provos and Mazieres in "A Future-Adaptable Password Scheme"
- # http:#www.openbsd.org/papers/bcrypt-paper.ps
+ # http://www.openbsd.org/papers/bcrypt-paper.ps
#
- #===========================================================
+ #===================================================================
engine = BlowfishEngine()
@@ -156,7 +156,7 @@ def raw_bcrypt(password, ident, salt, log_rounds):
rounds = 1<<log_rounds
engine.eks_rounds_expand0(pass_words, salt_words, rounds)
- #encipher constant data, and encode to bytes as digest.
+ # encipher constant data, and encode to bytes as digest.
data = list(BCRYPT_CDATA)
i = 0
while i < 6:
@@ -165,6 +165,6 @@ def raw_bcrypt(password, ident, salt, log_rounds):
raw = digest_struct.pack(*data)[:-1]
return bcrypt64.encode_bytes(raw)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/utils/_blowfish/_gen_files.py b/passlib/utils/_blowfish/_gen_files.py
index 6256bc5..a5757f2 100644
--- a/passlib/utils/_blowfish/_gen_files.py
+++ b/passlib/utils/_blowfish/_gen_files.py
@@ -1,7 +1,7 @@
"""passlib.utils._blowfish._gen_files - meta script that generates unrolled.py"""
-#==========================================================================
+#=============================================================================
# imports
-#==========================================================================
+#=============================================================================
# core
import os
import textwrap
@@ -9,9 +9,9 @@ import textwrap
from passlib.utils.compat import irange
# local
-#==========================================================================
+#=============================================================================
# helpers
-#==========================================================================
+#=============================================================================
def varlist(name, count):
return ", ".join(name + str(x) for x in irange(count))
@@ -65,7 +65,7 @@ def write_expand_function(write, indent=0):
write(indent, """\
def expand(self, key_words):
\"""unrolled version of blowfish key expansion\"""
- #assert len(key_words) >= 18, "size of key_words must be >= 18"
+ ##assert len(key_words) >= 18, "size of key_words must be >= 18"
P, S = self.P, self.S
S0, S1, S2, S3 = S
@@ -142,9 +142,9 @@ def write_expand_function(write, indent=0):
j += 2
""")
-#==========================================================================
+#=============================================================================
# main
-#==========================================================================
+#=============================================================================
def main():
target = os.path.join(os.path.dirname(__file__), "unrolled.py")
@@ -199,6 +199,6 @@ def main():
if __name__ == "__main__":
main()
-#==========================================================================
+#=============================================================================
# eof
-#==========================================================================
+#=============================================================================
diff --git a/passlib/utils/_blowfish/base.py b/passlib/utils/_blowfish/base.py
index e725e7f..65b6da0 100644
--- a/passlib/utils/_blowfish/base.py
+++ b/passlib/utils/_blowfish/base.py
@@ -1,20 +1,20 @@
"""passlib.utils._blowfish.base - unoptimized pure-python blowfish engine"""
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import struct
-#pkg
+# pkg
from passlib.utils.compat import bytes
from passlib.utils import repeat_string
-#local
+# local
__all__ = [
"BlowfishEngine",
]
-#=========================================================
+#=============================================================================
# blowfish constants
-#=========================================================
+#=============================================================================
BLOWFISH_P = BLOWFISH_S = None
def _init_constants():
@@ -304,9 +304,9 @@ def _init_constants():
]
]
-#=========================================================
+#=============================================================================
# engine
-#=========================================================
+#=============================================================================
class BlowfishEngine(object):
def __init__(self):
@@ -315,9 +315,9 @@ class BlowfishEngine(object):
self.P = list(BLOWFISH_P)
self.S = [ list(box) for box in BLOWFISH_S ]
- #=========================================================
+ #===================================================================
# common helpers
- #=========================================================
+ #===================================================================
@staticmethod
def key_to_words(data, size=18):
"""convert data to tuple of <size> 4-byte integers, repeating or
@@ -335,9 +335,9 @@ class BlowfishEngine(object):
# unpack
return struct.unpack(">%dI" % (size,), data)
- #=========================================================
+ #===================================================================
# blowfish routines
- #=========================================================
+ #===================================================================
def encipher(self, l, r):
"loop version of blowfish encipher routine"
P, S = self.P, self.S
@@ -375,9 +375,9 @@ class BlowfishEngine(object):
box[i], box[i+1] = l,r = encipher(l,r)
i += 2
- #=========================================================
+ #===================================================================
# eks-blowfish routines
- #=========================================================
+ #===================================================================
def eks_expand(self, key_words, salt_words):
"perform EKS version of Blowfish keyschedule setup"
# NOTE: this is the same as expand(), except for the addition
@@ -401,7 +401,7 @@ class BlowfishEngine(object):
s += 2
if s == salt_size:
s = 0
- P[i], P[i+1] = l,r = encipher(l,r) #next()
+ P[i], P[i+1] = l,r = encipher(l,r) # next()
i += 2
for box in S:
@@ -412,7 +412,7 @@ class BlowfishEngine(object):
s += 2
if s == salt_size:
s = 0
- box[i], box[i+1] = l,r = encipher(l,r) #next()
+ box[i], box[i+1] = l,r = encipher(l,r) # next()
i += 2
def eks_rounds_expand0(self, key_words, salt_words, rounds):
@@ -433,10 +433,10 @@ class BlowfishEngine(object):
n += 1
return l, r
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/utils/_blowfish/unrolled.py b/passlib/utils/_blowfish/unrolled.py
index aa504ea..7ce0bcc 100644
--- a/passlib/utils/_blowfish/unrolled.py
+++ b/passlib/utils/_blowfish/unrolled.py
@@ -4,18 +4,18 @@ autogenerated by _gen_files.py
currently this override the encipher() and expand() methods
with optimized versions, and leaves the other base.py methods alone.
"""
-#=================================================================
+#=============================================================================
# imports
-#=================================================================
+#=============================================================================
# pkg
from passlib.utils._blowfish.base import BlowfishEngine as _BlowfishEngine
# local
__all__ = [
"BlowfishEngine",
]
-#=================================================================
+#=============================================================================
#
-#=================================================================
+#=============================================================================
class BlowfishEngine(_BlowfishEngine):
def encipher(self, l, r):
@@ -88,7 +88,7 @@ class BlowfishEngine(_BlowfishEngine):
def expand(self, key_words):
"""unrolled version of blowfish key expansion"""
- #assert len(key_words) >= 18, "size of key_words must be >= 18"
+ ##assert len(key_words) >= 18, "size of key_words must be >= 18"
P, S = self.P, self.S
S0, S1, S2, S3 = S
@@ -762,10 +762,10 @@ class BlowfishEngine(_BlowfishEngine):
box[j], box[j+1] = l, r = r ^ p17, l
j += 2
- #=================================================================
+ #===================================================================
# eoc
- #=================================================================
+ #===================================================================
-#=================================================================
+#=============================================================================
# eof
-#=================================================================
+#=============================================================================
diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py
index 428e765..a7bb626 100644
--- a/passlib/utils/compat.py
+++ b/passlib/utils/compat.py
@@ -3,9 +3,9 @@
# figure out what we're running
#=============================================================================
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# python version
-#-----------------------------------------------------
+#------------------------------------------------------------------------
import sys
PY2 = sys.version_info < (3,0)
PY3 = sys.version_info >= (3,0)
@@ -13,15 +13,15 @@ PY_MAX_25 = sys.version_info < (2,6) # py 2.5 or earlier
PY27 = sys.version_info[:2] == (2,7) # supports last 2.x release
PY_MIN_32 = sys.version_info >= (3,2) # py 3.2 or later
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# python implementation
-#-----------------------------------------------------
+#------------------------------------------------------------------------
PYPY = hasattr(sys, "pypy_version_info")
JYTHON = sys.platform.startswith('java')
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# capabilities
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# __dir__() added in py2.6
SUPPORTS_DIR_METHOD = not PY_MAX_25 and not (PYPY and sys.pypy_version_info < (1,6))
diff --git a/passlib/utils/des.py b/passlib/utils/des.py
index 0422197..989e38a 100644
--- a/passlib/utils/des.py
+++ b/passlib/utils/des.py
@@ -37,11 +37,12 @@ The netbsd des-crypt implementation has some nice notes on how this all works -
http://fxr.googlebit.com/source/lib/libcrypt/crypt.c?v=NETBSD-CURRENT
"""
-#TODO: could use an accelerated C version of this module to speed up lmhash, des-crypt, and ext-des-crypt
+# TODO: could use an accelerated C version of this module to speed up lmhash,
+# des-crypt, and ext-des-crypt
-#=========================================================
-#imports
-#=========================================================
+#=============================================================================
+# imports
+#=============================================================================
# core
import struct
# pkg
@@ -56,9 +57,9 @@ __all__ = [
"mdes_encrypt_int_block",
]
-#=========================================================
+#=============================================================================
# constants
-#=========================================================
+#=============================================================================
# masks/upper limits for various integer sizes
INT_24_MASK = 0xffffff
@@ -72,9 +73,9 @@ _KPARITY_MASK = 0x0101010101010101
# mask used to setup key schedule
_KS_MASK = 0xfcfcfcfcffffffff
-#=========================================================
+#=============================================================================
# static DES tables
-#=========================================================
+#=============================================================================
# placeholders filled in by _load_tables()
PCXROT = IE3264 = SPE = CF6464 = None
@@ -83,11 +84,11 @@ def _load_tables():
"delay loading tables until they are actually needed"
global PCXROT, IE3264, SPE, CF6464
- #---------------------------------------------------
+ #---------------------------------------------------------------
# Initial key schedule permutation
# PC1ROT - bit reverse, then PC1, then Rotate, then PC2
- #---------------------------------------------------
- #NOTE: this was reordered from original table to make perm3264 logic simpler
+ #---------------------------------------------------------------
+ # NOTE: this was reordered from original table to make perm3264 logic simpler
PC1ROT=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000002000, 0x0000000000002000,
0x0000000000000020, 0x0000000000000020, 0x0000000000002020, 0x0000000000002020,
@@ -154,11 +155,11 @@ def _load_tables():
0x0000000800000000, 0x0000000880000000, 0x0000040800000000, 0x0000040880000000,
0x0010000800000000, 0x0010000880000000, 0x0010040800000000, 0x0010040880000000, ),
)
- #---------------------------------------------------
+ #---------------------------------------------------------------
# Subsequent key schedule rotation permutations
# PC2ROT - PC2 inverse, then Rotate, then PC2
- #---------------------------------------------------
- #NOTE: this was reordered from original table to make perm3264 logic simpler
+ #---------------------------------------------------------------
+ # NOTE: this was reordered from original table to make perm3264 logic simpler
PC2ROTA=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000200000, 0x0000000000200000, 0x0000000000200000, 0x0000000000200000,
@@ -226,7 +227,7 @@ def _load_tables():
0x0008200000000000, 0x0088200000000000, 0x0008240000000000, 0x0088240000000000, ),
)
- #NOTE: this was reordered from original table to make perm3264 logic simpler
+ # NOTE: this was reordered from original table to make perm3264 logic simpler
PC2ROTB=(
( 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000400, 0x0000000000000400, 0x0000000000000400, 0x0000000000000400,
@@ -293,10 +294,10 @@ def _load_tables():
0x0004000000000000, 0x0104000000000000, 0x0005000000000000, 0x0105000000000000,
0x0004001000000000, 0x0104001000000000, 0x0005001000000000, 0x0105001000000000, ),
)
- #---------------------------------------------------
- #PCXROT - PC1ROT, PC2ROTA, PC2ROTB listed in order
+ #---------------------------------------------------------------
+ # PCXROT - PC1ROT, PC2ROTA, PC2ROTB listed in order
# of the PC1 rotation schedule, as used by des_setkey
- #---------------------------------------------------
+ #---------------------------------------------------------------
##ROTATES = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1)
##PCXROT = (
## PC1ROT, PC2ROTA, PC2ROTB, PC2ROTB,
@@ -305,8 +306,8 @@ def _load_tables():
## PC2ROTB, PC2ROTB, PC2ROTB, PC2ROTA,
## )
- #NOTE: modified PCXROT to contain entrys broken into pairs,
- # to help generate them in format best used by encoder.
+ # NOTE: modified PCXROT to contain entrys broken into pairs,
+ # to help generate them in format best used by encoder.
PCXROT = (
(PC1ROT, PC2ROTA), (PC2ROTB, PC2ROTB),
(PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTB),
@@ -314,11 +315,11 @@ def _load_tables():
(PC2ROTB, PC2ROTB), (PC2ROTB, PC2ROTA),
)
- #---------------------------------------------------
+ #---------------------------------------------------------------
# Bit reverse, intial permupation, expantion
# Initial permutation/expansion table
- #---------------------------------------------------
- #NOTE: this was reordered from original table to make perm3264 logic simpler
+ #---------------------------------------------------------------
+ # NOTE: this was reordered from original table to make perm3264 logic simpler
IE3264=(
( 0x0000000000000000, 0x0000000000800800, 0x0000000000008008, 0x0000000000808808,
0x0000008008000000, 0x0000008008800800, 0x0000008008008008, 0x0000008008808808,
@@ -354,9 +355,9 @@ def _load_tables():
0x4044040000000000, 0x4044440400000000, 0x4044044004000000, 0x4044444404000000, ),
)
- #---------------------------------------------------
+ #---------------------------------------------------------------
# Table that combines the S, P, and E operations.
- #---------------------------------------------------
+ #---------------------------------------------------------------
SPE=(
( 0x0080088008200000, 0x0000008008000000, 0x0000000000200020, 0x0080088008200020,
0x0000000000200000, 0x0080088008000020, 0x0000008008000020, 0x0000000000200020,
@@ -488,11 +489,11 @@ def _load_tables():
0x0000000000002000, 0x8008000080082000, 0x0000002000000000, 0x8008002080080000, ),
)
- #---------------------------------------------------
+ #---------------------------------------------------------------
# compressed/interleaved => final permutation table
# Compression, final permutation, bit reverse
- #---------------------------------------------------
- #NOTE: this was reordered from original table to make perm6464 logic simpler
+ #---------------------------------------------------------------
+ # NOTE: this was reordered from original table to make perm6464 logic simpler
CF6464=(
( 0x0000000000000000, 0x0000002000000000, 0x0000200000000000, 0x0000202000000000,
0x0020000000000000, 0x0020002000000000, 0x0020200000000000, 0x0020202000000000,
@@ -559,28 +560,28 @@ def _load_tables():
0x0000000004000000, 0x0000000004000004, 0x0000000004000400, 0x0000000004000404,
0x0000000004040000, 0x0000000004040004, 0x0000000004040400, 0x0000000004040404, ),
)
- #=========================================================
+ #===================================================================
# eof _load_tables()
- #=========================================================
+ #===================================================================
-#=========================================================
+#=============================================================================
# support
-#=========================================================
+#=============================================================================
def _permute(c, p):
"""Returns the permutation of the given 32-bit or 64-bit code with
the specified permutation table."""
- #NOTE: only difference between 32 & 64 bit permutations
- #is that len(p)==8 for 32 bit, and len(p)==16 for 64 bit.
+ # NOTE: only difference between 32 & 64 bit permutations
+ # is that len(p)==8 for 32 bit, and len(p)==16 for 64 bit.
out = 0
for r in p:
out |= r[c&0xf]
c >>= 4
return out
-#=========================================================
+#=============================================================================
# packing & unpacking
-#=========================================================
+#=============================================================================
_uint64_struct = struct.Struct(">Q")
_BNULL = b('\x00')
@@ -597,9 +598,9 @@ def _pack56(value):
def _unpack56(value):
return _uint64_struct.unpack(_BNULL+value)[0]
-#=========================================================
+#=============================================================================
# 56->64 key manipulation
-#=========================================================
+#=============================================================================
##def expand_7bit(value):
## "expand 7-bit integer => 7-bits + 1 odd-parity bit"
@@ -650,9 +651,9 @@ def shrink_des_key(key):
assert not (result & ~INT_64_MASK)
return result
-#=========================================================
+#=============================================================================
# des encryption
-#=========================================================
+#=============================================================================
def des_encrypt_block(key, input, salt=0, rounds=1):
"""encrypt single block of data using DES, operates on 8-byte strings.
@@ -738,9 +739,9 @@ def des_encrypt_int_block(key, input, salt=0, rounds=1):
:returns:
resulting ciphertext as 64-bit integer.
"""
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# input validation
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# validate salt, rounds
if rounds < 1:
@@ -760,9 +761,9 @@ def des_encrypt_int_block(key, input, salt=0, rounds=1):
elif input < 0 or input > INT_64_MASK:
raise ValueError("input must be 64-bit non-negative integer")
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# DES setup
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# load tables if not already done
global SPE, PCXROT, IE3264, CF6464
if PCXROT is None:
@@ -803,9 +804,9 @@ def des_encrypt_int_block(key, input, salt=0, rounds=1):
R = ((input >> 32) & 0xaaaaaaaa) | ((input >> 1) & 0x55555555)
R = _permute(R, IE3264)
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# main DES loop - run for specified number of rounds
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
while rounds:
rounds -= 1
@@ -830,9 +831,9 @@ def des_encrypt_int_block(key, input, salt=0, rounds=1):
# swap L and R
L, R = R, L
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
# return final result
- #-------------------------------------------------------------------
+ #---------------------------------------------------------------
C = (
((L>>3) & 0x0f0f0f0f00000000)
|
@@ -853,6 +854,6 @@ def mdes_encrypt_int_block(key, input, salt=0, rounds=1): # pragma: no cover --
key = _unpack64(key)
return des_encrypt_int_block(key, input, salt, rounds)
-#=========================================================
-#eof
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/utils/handlers.py b/passlib/utils/handlers.py
index 22421f6..4385f3b 100644
--- a/passlib/utils/handlers.py
+++ b/passlib/utils/handlers.py
@@ -1,7 +1,7 @@
"""passlib.handler - code for implementing handlers, and global registry for handlers"""
-#=========================================================
+#=============================================================================
# imports
-#=========================================================
+#=============================================================================
from __future__ import with_statement
# core
import inspect
@@ -48,9 +48,9 @@ __all__ = [
'PrefixWrapper',
]
-#=========================================================
-#constants
-#=========================================================
+#=============================================================================
+# constants
+#=============================================================================
# common salt_chars & checksum_chars values
# (BASE64_CHARS, HASH64_CHARS imported above)
@@ -59,7 +59,7 @@ HEX_CHARS = u("0123456789abcdefABCDEF")
UPPER_HEX_CHARS = u("0123456789ABCDEF")
LOWER_HEX_CHARS = u("0123456789abcdef")
-#: special byte string containing all possible byte values
+# special byte string containing all possible byte values
# XXX: treated as singleton by some of the code for efficiency.
ALL_BYTE_VALUES = join_byte_values(irange(256))
@@ -70,9 +70,9 @@ PADDED_B64_CHARS = PADDED_BASE64_CHARS
UC_HEX_CHARS = UPPER_HEX_CHARS
LC_HEX_CHARS = LOWER_HEX_CHARS
-#=========================================================
+#=============================================================================
# support functions
-#=========================================================
+#=============================================================================
def _bitsize(count, chars):
"""helper for bitsize() methods"""
if chars and count:
@@ -81,9 +81,9 @@ def _bitsize(count, chars):
else:
return 0
-#=========================================================
+#=============================================================================
# parsing helpers
-#=========================================================
+#=============================================================================
_UDOLLAR = u("$")
_UZERO = u("0")
@@ -192,9 +192,9 @@ def parse_mc3(hash, prefix, sep=_UDOLLAR, rounds_base=10,
# return result
return rounds, salt, chk or None
-#=====================================================
-#formatting helpers
-#=====================================================
+#=============================================================================
+# formatting helpers
+#=============================================================================
def render_mc2(ident, salt, checksum, sep=u("$")):
"""format hash using 2-part modular crypt format; inverse of parse_mc2()
@@ -244,9 +244,9 @@ def render_mc3(ident, rounds, salt, checksum, sep=u("$"), rounds_base=10):
parts = [ident, rounds, sep, salt]
return uascii_to_str(join_unicode(parts))
-#=====================================================
-#GenericHandler
-#=====================================================
+#=============================================================================
+# GenericHandler
+#=============================================================================
class GenericHandler(PasswordHash):
"""helper class for implementing hash handlers.
@@ -361,9 +361,9 @@ class GenericHandler(PasswordHash):
.. automethod:: verify
"""
- #=====================================================
- #class attr
- #=====================================================
+ #===================================================================
+ # class attr
+ #===================================================================
# this must be provided by the actual class.
setting_kwds = None
@@ -390,16 +390,16 @@ class GenericHandler(PasswordHash):
# private flag used by HasRawChecksum
_checksum_is_bytes = False
- #=====================================================
- #instance attrs
- #=====================================================
+ #===================================================================
+ # instance attrs
+ #===================================================================
checksum = None # stores checksum
# use_defaults = False # whether _norm_xxx() funcs should fill in defaults.
# relaxed = False # when _norm_xxx() funcs should be strict about inputs
- #=====================================================
- #init
- #=====================================================
+ #===================================================================
+ # init
+ #===================================================================
def __init__(self, checksum=None, use_defaults=False, relaxed=False,
**kwds):
self.use_defaults = use_defaults
@@ -451,9 +451,9 @@ class GenericHandler(PasswordHash):
return checksum
- #=====================================================
- #password hash api - formatting interface
- #=====================================================
+ #===================================================================
+ # password hash api - formatting interface
+ #===================================================================
@classmethod
def identify(cls, hash):
# NOTE: subclasses may wish to use faster / simpler identify,
@@ -482,7 +482,7 @@ class GenericHandler(PasswordHash):
return False
@classmethod
- def from_string(cls, hash, **context): #pragma: no cover
+ def from_string(cls, hash, **context): # pragma: no cover
"""return parsed instance from hash/configuration string
:param \*\*context:
@@ -496,7 +496,7 @@ class GenericHandler(PasswordHash):
"""
raise NotImplementedError("%s must implement from_string()" % (cls,))
- def to_string(self): #pragma: no cover
+ def to_string(self): # pragma: no cover
"""render instance to hash or configuration string
:returns:
@@ -507,10 +507,10 @@ class GenericHandler(PasswordHash):
should return native string type (ascii-bytes under python 2,
unicode under python 3)
"""
- #NOTE: documenting some non-standardized but common kwd flags
- # that passlib to_string() method may have
+ # NOTE: documenting some non-standardized but common kwd flags
+ # that passlib to_string() method may have:
#
- # withchk=True -- if false, omit checksum portion of hash
+ # withchk=True -- if false, omit checksum portion of hash
#
raise NotImplementedError("%s must implement from_string()" %
(self.__class__,))
@@ -524,9 +524,9 @@ class GenericHandler(PasswordHash):
## finally:
## self.checksum = orig
- #=========================================================
+ #===================================================================
#'crypt-style' interface (default implementation)
- #=========================================================
+ #===================================================================
@classmethod
def genconfig(cls, **settings):
return cls(use_defaults=True, **settings).to_string()
@@ -538,7 +538,7 @@ class GenericHandler(PasswordHash):
self.checksum = self._calc_checksum(secret)
return self.to_string()
- def _calc_checksum(self, secret): #pragma: no cover
+ def _calc_checksum(self, secret): # pragma: no cover
"""given secret; calcuate and return encoded checksum portion of hash
string, taking config from object state
@@ -548,9 +548,9 @@ class GenericHandler(PasswordHash):
raise NotImplementedError("%s must implement _calc_checksum()" %
(self.__class__,))
- #=========================================================
+ #===================================================================
#'application' interface (default implementation)
- #=========================================================
+ #===================================================================
@classmethod
def encrypt(cls, secret, **kwds):
validate_secret(secret)
@@ -570,10 +570,10 @@ class GenericHandler(PasswordHash):
raise exc.MissingDigestError(cls)
return consteq(self._calc_checksum(secret), chk)
- #=========================================================
+ #===================================================================
# experimental - the following methods are not finished or tested,
# but way work correctly for some hashes
- #=========================================================
+ #===================================================================
_unparsed_settings = ("salt_size", "relaxed")
_unsafe_settings = ("salt", "checksum")
@@ -646,9 +646,9 @@ class GenericHandler(PasswordHash):
info['checksum'] = _bitsize(cls.checksum_size, cc)
return info
- #=========================================================
+ #===================================================================
# eoc
- #=========================================================
+ #===================================================================
class StaticHandler(GenericHandler):
"""GenericHandler mixin for classes which have no settings.
@@ -741,9 +741,9 @@ class StaticHandler(GenericHandler):
DeprecationWarning)
return str_to_uascii(hash)
-#=====================================================
-#GenericHandler mixin classes
-#=====================================================
+#=============================================================================
+# GenericHandler mixin classes
+#=============================================================================
class HasEncodingContext(GenericHandler):
"""helper for classes which require knowledge of the encoding used"""
context_kwds = ("encoding",)
@@ -788,9 +788,9 @@ class HasUserContext(GenericHandler):
## info['user'] = xxx
## return info
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# checksum mixins
-#-----------------------------------------------------
+#------------------------------------------------------------------------
class HasRawChecksum(GenericHandler):
"""mixin for classes which work with decoded checksum bytes
@@ -805,9 +805,9 @@ class HasRawChecksum(GenericHandler):
# this arrangement may be changed in the future.
_checksum_is_bytes = True
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# ident mixins
-#-----------------------------------------------------
+#------------------------------------------------------------------------
class HasManyIdents(GenericHandler):
"""mixin for hashes which use multiple prefix identifiers
@@ -823,27 +823,27 @@ class HasManyIdents(GenericHandler):
document this class's usage
"""
- #=========================================================
- #class attrs
- #=========================================================
- default_ident = None #: should be unicode
- ident_values = None #: should be list of unicode strings
- ident_aliases = None #: should be dict of unicode -> unicode
- #NOTE: any aliases provided to norm_ident() as bytes
- # will have been converted to unicode before
- # comparing against this dictionary.
-
- #NOTE: relying on test_06_HasManyIdents() to verify
- # these are configured correctly.
-
- #=========================================================
- #instance attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
+ default_ident = None # should be unicode
+ ident_values = None # should be list of unicode strings
+ ident_aliases = None # should be dict of unicode -> unicode
+ # NOTE: any aliases provided to norm_ident() as bytes
+ # will have been converted to unicode before
+ # comparing against this dictionary.
+
+ # NOTE: relying on test_06_HasManyIdents() to verify
+ # these are configured correctly.
+
+ #===================================================================
+ # instance attrs
+ #===================================================================
ident = None
- #=========================================================
- #init
- #=========================================================
+ #===================================================================
+ # init
+ #===================================================================
def __init__(self, ident=None, **kwds):
super(HasManyIdents, self).__init__(**kwds)
self.ident = self._norm_ident(ident)
@@ -879,9 +879,9 @@ class HasManyIdents(GenericHandler):
# failure!
raise ValueError("invalid ident: %r" % (ident,))
- #=========================================================
- #password hash api
- #=========================================================
+ #===================================================================
+ # password hash api
+ #===================================================================
@classmethod
def identify(cls, hash):
hash = to_unicode_for_identify(hash)
@@ -896,13 +896,13 @@ class HasManyIdents(GenericHandler):
return ident, hash[len(ident):]
raise exc.InvalidHashError(cls)
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# salt mixins
-#-----------------------------------------------------
+#------------------------------------------------------------------------
class HasSalt(GenericHandler):
"""mixin for validating salts.
@@ -976,9 +976,9 @@ class HasSalt(GenericHandler):
# TODO: document _truncate_salt()
# XXX: allow providing raw salt to this class, and encoding it?
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
min_salt_size = None
max_salt_size = None
@@ -998,14 +998,14 @@ class HasSalt(GenericHandler):
_salt_is_bytes = False
_salt_unit = "chars"
- #=========================================================
- #instance attrs
- #=========================================================
+ #===================================================================
+ # instance attrs
+ #===================================================================
salt = None
- #=========================================================
- #init
- #=========================================================
+ #===================================================================
+ # init
+ #===================================================================
def __init__(self, salt=None, salt_size=None, **kwds):
super(HasSalt, self).__init__(**kwds)
self.salt = self._norm_salt(salt, salt_size=salt_size)
@@ -1104,9 +1104,9 @@ class HasSalt(GenericHandler):
info['salt'] = _bitsize(salt_size, cls.default_salt_chars)
return info
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
class HasRawSalt(HasSalt):
"""mixin for classes which use decoded salt parameter
@@ -1129,9 +1129,9 @@ class HasRawSalt(HasSalt):
assert self.salt_chars in [None, ALL_BYTE_VALUES]
return getrandbytes(rng, salt_size)
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# rounds mixin
-#-----------------------------------------------------
+#------------------------------------------------------------------------
class HasRounds(GenericHandler):
"""mixin for validating rounds parameter
@@ -1182,22 +1182,22 @@ class HasRounds(GenericHandler):
====================
.. automethod:: _norm_rounds
"""
- #=========================================================
- #class attrs
- #=========================================================
+ #===================================================================
+ # class attrs
+ #===================================================================
min_rounds = 0
max_rounds = None
default_rounds = None
rounds_cost = "linear" # default to the common case
- #=========================================================
- #instance attrs
- #=========================================================
+ #===================================================================
+ # instance attrs
+ #===================================================================
rounds = None
- #=========================================================
- #init
- #=========================================================
+ #===================================================================
+ # init
+ #===================================================================
def __init__(self, rounds=None, **kwds):
super(HasRounds, self).__init__(**kwds)
self.rounds = self._norm_rounds(rounds)
@@ -1279,13 +1279,13 @@ class HasRounds(GenericHandler):
# the time-cost, and can't be randomized.
return info
- #=========================================================
- #eoc
- #=========================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#-----------------------------------------------------
+#------------------------------------------------------------------------
# backend mixin & helpers
-#-----------------------------------------------------
+#------------------------------------------------------------------------
##def _clear_backend(cls):
## "restore HasManyBackend subclass to unloaded state - used by unittests"
## assert issubclass(cls, HasManyBackends) and cls is not HasManyBackends
@@ -1339,14 +1339,15 @@ class HasManyBackends(GenericHandler):
by the subclass for each backend listed in :attr:`backends`.
"""
- #NOTE: subclass must provide:
- # * attr 'backends' containing list of known backends (top priority backend first)
- # * attr '_has_backend_xxx' for each backend 'xxx', indicating if backend is available on system
- # * attr '_calc_checksum_xxx' for each backend 'xxx', containing calc_checksum implementation using that backend
+ # NOTE:
+ # subclass must provide:
+ # * attr 'backends' containing list of known backends (top priority backend first)
+ # * attr '_has_backend_xxx' for each backend 'xxx', indicating if backend is available on system
+ # * attr '_calc_checksum_xxx' for each backend 'xxx', containing calc_checksum implementation using that backend
- backends = None #: list of backend names, provided by subclass.
+ backends = None # list of backend names, provided by subclass.
- _backend = None #: holds currently loaded backend (if any) or None
+ _backend = None # holds currently loaded backend (if any) or None
@classmethod
def get_backend(cls):
@@ -1456,9 +1457,9 @@ class HasManyBackends(GenericHandler):
# this should now invoke the backend-specific version, so call it again.
return self._calc_checksum(secret)
-#=========================================================
-#wrappers
-#=========================================================
+#=============================================================================
+# wrappers
+#=============================================================================
class PrefixWrapper(object):
"""wraps another handler, adding a constant prefix.
@@ -1518,7 +1519,7 @@ class PrefixWrapper(object):
def _check_handler(self, handler):
if 'ident' in handler.setting_kwds and self.orig_prefix:
- #TODO: look into way to fix the issues.
+ # TODO: look into way to fix the issues.
warn("PrefixWrapper: 'orig_prefix' option may not work correctly "
"for handlers which have multiple identifiers: %r" %
(handler.name,), exc.PasslibRuntimeWarning)
@@ -1571,7 +1572,7 @@ class PrefixWrapper(object):
self._ident_values = value
return value
- #attrs that should be proxied
+ # attrs that should be proxied
_proxy_attrs = (
"setting_kwds", "context_kwds",
"default_rounds", "min_rounds", "max_rounds", "rounds_cost",
@@ -1600,7 +1601,7 @@ class PrefixWrapper(object):
return list(attrs)
def __getattr__(self, attr):
- "proxy most attributes from wrapped class (eg rounds, salt size, etc)"
+ "proxy most attributes from wrapped class (e.g. rounds, salt size, etc)"
if attr in self._proxy_attrs:
return getattr(self.wrapped, attr)
raise AttributeError("missing attribute: %r" % (attr,))
@@ -1611,7 +1612,7 @@ class PrefixWrapper(object):
prefix = self.prefix
if not hash.startswith(prefix):
raise exc.InvalidHashError(self)
- #NOTE: always passing to handler as unicode, to save reconversion
+ # NOTE: always passing to handler as unicode, to save reconversion
return self.orig_prefix + hash[len(prefix):]
def _wrap_hash(self, hash):
@@ -1654,6 +1655,6 @@ class PrefixWrapper(object):
hash = self._unwrap_hash(hash)
return self.wrapped.verify(secret, hash, **kwds)
-#=========================================================
+#=============================================================================
# eof
-#=========================================================
+#=============================================================================
diff --git a/passlib/utils/md4.py b/passlib/utils/md4.py
index 63f0d1b..cdc1493 100644
--- a/passlib/utils/md4.py
+++ b/passlib/utils/md4.py
@@ -7,20 +7,20 @@ implementated based on rfc at http://www.faqs.org/rfcs/rfc1320.html
"""
-#=========================================================================
-#imports
-#=========================================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify
import struct
from warnings import warn
-#site
+# site
from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY3
-#local
+# local
__all__ = [ "md4" ]
-#=========================================================================
-#utils
-#=========================================================================
+#=============================================================================
+# utils
+#=============================================================================
def F(x,y,z):
return (x&y) | ((~x) & z)
@@ -32,9 +32,9 @@ def G(x,y,z):
MASK_32 = 2**32-1
-#=========================================================================
-#main class
-#=========================================================================
+#=============================================================================
+# main class
+#=============================================================================
class md4(object):
"""pep-247 compatible implementation of MD4 hash algorithm
@@ -58,16 +58,16 @@ class md4(object):
return hexdecimal version of digest
"""
- #FIXME: make this follow hash object PEP better.
- #FIXME: this isn't threadsafe
- #XXX: should we monkeypatch ourselves into hashlib for general use? probably wouldn't be nice.
+ # FIXME: make this follow hash object PEP better.
+ # FIXME: this isn't threadsafe
+ # XXX: should we monkeypatch ourselves into hashlib for general use? probably wouldn't be nice.
name = "md4"
digest_size = digestsize = 16
- _count = 0 #number of 64-byte blocks processed so far (not including _buf)
- _state = None #list of [a,b,c,d] 32 bit ints used as internal register
- _buf = None #data processed in 64 byte blocks, this holds leftover from last update
+ _count = 0 # number of 64-byte blocks processed so far (not including _buf)
+ _state = None # list of [a,b,c,d] 32 bit ints used as internal register
+ _buf = None # data processed in 64 byte blocks, this holds leftover from last update
def __init__(self, content=None):
self._count = 0
@@ -76,7 +76,7 @@ class md4(object):
if content:
self.update(content)
- #round 1 table - [abcd k s]
+ # round 1 table - [abcd k s]
_round1 = [
[0,1,2,3, 0,3],
[3,0,1,2, 1,7],
@@ -99,7 +99,7 @@ class md4(object):
[1,2,3,0, 15,19],
]
- #round 2 table - [abcd k s]
+ # round 2 table - [abcd k s]
_round2 = [
[0,1,2,3, 0,3],
[3,0,1,2, 4,5],
@@ -122,7 +122,7 @@ class md4(object):
[1,2,3,0, 15,13],
]
- #round 3 table - [abcd k s]
+ # round 3 table - [abcd k s]
_round3 = [
[0,1,2,3, 0,3],
[3,0,1,2, 8,9],
@@ -147,29 +147,29 @@ class md4(object):
def _process(self, block):
"process 64 byte block"
- #unpack block into 16 32-bit ints
+ # unpack block into 16 32-bit ints
X = struct.unpack("<16I", block)
- #clone state
+ # clone state
orig = self._state
state = list(orig)
- #round 1 - F function - (x&y)|(~x & z)
+ # round 1 - F function - (x&y)|(~x & z)
for a,b,c,d,k,s in self._round1:
t = (state[a] + F(state[b],state[c],state[d]) + X[k]) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
- #round 2 - G function
+ # round 2 - G function
for a,b,c,d,k,s in self._round2:
t = (state[a] + G(state[b],state[c],state[d]) + X[k] + 0x5a827999) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
- #round 3 - H function - x ^ y ^ z
+ # round 3 - H function - x ^ y ^ z
for a,b,c,d,k,s in self._round3:
t = (state[a] + (state[b] ^ state[c] ^ state[d]) + X[k] + 0x6ed9eba1) & MASK_32
state[a] = ((t<<s) & MASK_32) + (t>>(32-s))
- #add back into original state
+ # add back into original state
for i in irange(4):
orig[i] = (orig[i]+state[i]) & MASK_32
@@ -199,11 +199,11 @@ class md4(object):
return other
def digest(self):
- #NOTE: backing up state so we can restore it after _process is called,
- #in case object is updated again (this is only attr altered by this method)
+ # NOTE: backing up state so we can restore it after _process is called,
+ # in case object is updated again (this is only attr altered by this method)
orig = list(self._state)
- #final block: buf + 0x80,
+ # final block: buf + 0x80,
# then 0x00 padding until congruent w/ 56 mod 64 bytes
# then last 8 bytes = msg length in bits
buf = self._buf
@@ -217,7 +217,7 @@ class md4(object):
assert len(block) == 64
self._process(block)
- #render digest & restore un-finalized state
+ # render digest & restore un-finalized state
out = struct.pack("<4I", *self._state)
self._state = orig
return out
@@ -225,16 +225,16 @@ class md4(object):
def hexdigest(self):
return bascii_to_str(hexlify(self.digest()))
- #=========================================================================
- #eoc
- #=========================================================================
+ #===================================================================
+ # eoc
+ #===================================================================
-#keep ref around for unittest, 'md4' usually replaced by ssl wrapper, below.
+# keep ref around for unittest, 'md4' usually replaced by ssl wrapper, below.
_builtin_md4 = md4
-#=========================================================================
-#check if hashlib provides accelarated md4
-#=========================================================================
+#=============================================================================
+# check if hashlib provides accelarated md4
+#=============================================================================
import hashlib
from passlib.utils import PYPY
@@ -256,11 +256,11 @@ def _has_native_md4(): # pragma: no cover -- runtime detection
return False
if _has_native_md4():
- #overwrite md4 class w/ hashlib wrapper
+ # overwrite md4 class w/ hashlib wrapper
def md4(content=None):
"wrapper for hashlib.new('md4')"
return hashlib.new('md4', content or b(''))
-#=========================================================================
-#eof
-#=========================================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py
index 916b295..1cd0d8f 100644
--- a/passlib/utils/pbkdf2.py
+++ b/passlib/utils/pbkdf2.py
@@ -3,25 +3,25 @@
this module is getting increasingly poorly named.
maybe rename to "kdf" since it's getting more key derivation functions added.
"""
-#=================================================================================
-#imports
-#=================================================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
import hashlib
import logging; log = logging.getLogger(__name__)
import re
from struct import pack
from warnings import warn
-#site
+# site
try:
from M2Crypto import EVP as _EVP
except ImportError:
_EVP = None
-#pkg
+# pkg
from passlib.exc import PasslibRuntimeWarning, ExpectedTypeError
from passlib.utils import join_bytes, to_native_str, bytes_to_int, int_to_bytes, join_byte_values
from passlib.utils.compat import b, bytes, BytesIO, irange, callable, int_types
-#local
+# local
__all__ = [
"get_prf",
"pbkdf1",
@@ -132,9 +132,9 @@ def norm_hash_name(name, format="hashlib"):
# TODO: get_hash() func which wraps norm_hash_name(), hashlib.<attr>, and hashlib.new
-#=================================================================================
-#general prf lookup
-#=================================================================================
+#=============================================================================
+# general prf lookup
+#=============================================================================
_BNULL = b('\x00')
_XY_DIGEST = b(',\x1cb\xe0H\xa5\x82M\xfb>\xd6\x98\xef\x8e\xf9oQ\x85\xa3i')
@@ -153,7 +153,7 @@ def _get_hmac_prf(digest):
# use m2crypto function directly for sha1, since that's it's default digest
try:
result = _EVP.hmac(b('x'),b('y'))
- except ValueError: #pragma: no cover
+ except ValueError: # pragma: no cover
pass
else:
if result == _XY_DIGEST:
@@ -168,7 +168,7 @@ def _get_hmac_prf(digest):
except ValueError:
pass
else:
- #it does. so use M2Crypto's hmac & digest code
+ # it does. so use M2Crypto's hmac & digest code
hmac_const = _EVP.hmac
def prf(key, msg):
return hmac_const(key, msg, digest)
@@ -176,7 +176,7 @@ def _get_hmac_prf(digest):
tag_wrapper(prf)
return prf, digest_size
- #fall back to hashlib-based implementation
+ # fall back to hashlib-based implementation
digest_const = getattr(hashlib, digest, None)
if not digest_const:
raise ValueError("unknown hash algorithm: %r" % (digest,))
@@ -195,7 +195,7 @@ def _get_hmac_prf(digest):
tag_wrapper(prf)
return prf, digest_size
-#cache mapping prf name/func -> (func, digest_size)
+# cache mapping prf name/func -> (func, digest_size)
_prf_cache = {}
def _clear_prf_cache():
@@ -252,7 +252,7 @@ def get_prf(name):
else:
raise ValueError("unknown prf algorithm: %r" % (name,))
elif callable(name):
- #assume it's a callable, use it directly
+ # assume it's a callable, use it directly
digest_size = len(name(b('x'),b('y')))
retval = (name, digest_size)
else:
@@ -260,9 +260,9 @@ def get_prf(name):
_prf_cache[name] = retval
return retval
-#=================================================================================
-#pbkdf1 support
-#=================================================================================
+#=============================================================================
+# pbkdf1 support
+#=============================================================================
def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
"""pkcs#5 password-based key derivation v1.5
@@ -326,10 +326,10 @@ def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
block = hash_const(block).digest()
return block[:keylen]
-#=================================================================================
-#pbkdf2
-#=================================================================================
-MAX_BLOCKS = 0xffffffff #2**32-1
+#=============================================================================
+# pbkdf2
+#=============================================================================
+MAX_BLOCKS = 0xffffffff # 2**32-1
MAX_HMAC_SHA1_KEYLEN = MAX_BLOCKS*20
# NOTE: the pbkdf2 spec does not specify a maximum number of rounds.
# however, many of the hashes in passlib are currently clamped
@@ -399,7 +399,7 @@ def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
if block_count >= MAX_BLOCKS:
raise ValueError("key length too long for digest")
- #build up result from blocks
+ # build up result from blocks
def gen():
for i in irange(block_count):
digest = prf_func(secret, salt + pack(">L", i+1))
@@ -410,6 +410,6 @@ def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
yield int_to_bytes(accum, digest_size)
return join_bytes(gen())[:keylen]
-#=================================================================================
-#eof
-#=================================================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/passlib/win32.py b/passlib/win32.py
index 44fa435..7815597 100644
--- a/passlib/win32.py
+++ b/passlib/win32.py
@@ -27,42 +27,42 @@ warn("the 'passlib.win32' module is deprecated, and will be removed in "
"'passlib.hash.lmhash' classes instead.",
DeprecationWarning)
-#=========================================================
-#imports
-#=========================================================
-#core
+#=============================================================================
+# imports
+#=============================================================================
+# core
from binascii import hexlify
-#site
-#pkg
+# site
+# pkg
from passlib.utils.compat import b, unicode
from passlib.utils.des import des_encrypt_block
from passlib.hash import nthash
-#local
+# local
__all__ = [
"nthash",
"raw_lmhash",
"raw_nthash",
]
-#=========================================================
-#helpers
-#=========================================================
+#=============================================================================
+# helpers
+#=============================================================================
LM_MAGIC = b("KGS!@#$%")
raw_nthash = nthash.raw_nthash
def raw_lmhash(secret, encoding="ascii", hex=False):
"encode password using des-based LMHASH algorithm; returns string of raw bytes, or unicode hex"
- #NOTE: various references say LMHASH uses the OEM codepage of the host
- # for it's encoding. until a clear reference is found,
- # as well as a path for getting the encoding,
- # letting this default to "ascii" to prevent incorrect hashes
- # from being made w/o user explicitly choosing an encoding.
+ # NOTE: various references say LMHASH uses the OEM codepage of the host
+ # for it's encoding. until a clear reference is found,
+ # as well as a path for getting the encoding,
+ # letting this default to "ascii" to prevent incorrect hashes
+ # from being made w/o user explicitly choosing an encoding.
if isinstance(secret, unicode):
secret = secret.encode(encoding)
ns = secret.upper()[:14] + b("\x00") * (14-len(secret))
out = des_encrypt_block(ns[:7], LM_MAGIC) + des_encrypt_block(ns[7:], LM_MAGIC)
return hexlify(out).decode("ascii") if hex else out
-#=========================================================
-#eoc
-#=========================================================
+#=============================================================================
+# eoc
+#=============================================================================
diff --git a/setup.py b/setup.py
index 44dea01..ff0b901 100644
--- a/setup.py
+++ b/setup.py
@@ -1,14 +1,14 @@
"""passlib setup script"""
-#=========================================================
+#=============================================================================
# init script env -- ensure cwd = root of source dir
-#=========================================================
+#=============================================================================
import os
root_dir = os.path.abspath(os.path.join(__file__,".."))
os.chdir(root_dir)
-#=========================================================
+#=============================================================================
# imports
-#=========================================================
+#=============================================================================
import re
import sys
import time
@@ -22,24 +22,24 @@ except ImportError:
from distutils.core import setup
has_distribute = False
-#=========================================================
+#=============================================================================
# init setup options
-#=========================================================
+#=============================================================================
opts = { "cmdclass": { } }
args = sys.argv[1:]
-#=========================================================
-#register docdist command (not required)
-#=========================================================
+#=============================================================================
+# register docdist command (not required)
+#=============================================================================
try:
from passlib._setup.docdist import docdist
opts['cmdclass']['docdist'] = docdist
except ImportError:
pass
-#=========================================================
+#=============================================================================
# version string / datestamps
-#=========================================================
+#=============================================================================
from passlib import __version__ as VERSION
# if this is an hg checkout of passlib, add datestamp to version string.
@@ -75,9 +75,9 @@ if os.path.exists(os.path.join(root_dir, "passlib.komodoproject")):
from passlib._setup.stamp import stamp_distutils_output
stamp_distutils_output(opts, VERSION)
-#=========================================================
-#static text
-#=========================================================
+#=============================================================================
+# static text
+#=============================================================================
SUMMARY = "comprehensive password hashing framework supporting over 30 schemes"
DESCRIPTION = """\
@@ -130,12 +130,12 @@ else:
is_release = True
CLASSIFIERS.append("Development Status :: 5 - Production/Stable")
-#=========================================================
-#run setup
-#=========================================================
+#=============================================================================
+# run setup
+#=============================================================================
# XXX: could omit 'passlib._setup' from eggs, but not sdist
setup(
- #package info
+ # package info
packages = [
"passlib",
"passlib.ext",
@@ -149,7 +149,7 @@ setup(
package_data = { "passlib.tests": ["*.cfg"] },
zip_safe=True,
- #metadata
+ # metadata
name = "passlib",
version = VERSION,
author = "Eli Collins",
@@ -169,10 +169,10 @@ setup(
tests_require = 'nose >= 1.1',
test_suite = 'nose.collector',
- #extra opts
+ # extra opts
script_args=args,
**opts
)
-#=========================================================
-#EOF
-#=========================================================
+#=============================================================================
+# eof
+#=============================================================================
diff --git a/tox.ini b/tox.ini
index e51cf73..b733e01 100644
--- a/tox.ini
+++ b/tox.ini
@@ -138,5 +138,5 @@ commands =
nosetests --with-gae --without-sandbox {posargs:passlib/tests}
#===========================================================================
-# EOF
+# eof
#===========================================================================