Загрузить файлы в «venv/Lib/site-packages/passlib»
This commit is contained in:
3
venv/Lib/site-packages/passlib/__init__.py
Normal file
3
venv/Lib/site-packages/passlib/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""passlib - suite of password hashing & generation routines"""
|
||||||
|
|
||||||
|
__version__ = '1.7.4'
|
||||||
1255
venv/Lib/site-packages/passlib/apache.py
Normal file
1255
venv/Lib/site-packages/passlib/apache.py
Normal file
File diff suppressed because it is too large
Load Diff
245
venv/Lib/site-packages/passlib/apps.py
Normal file
245
venv/Lib/site-packages/passlib/apps.py
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
"""passlib.apps"""
|
||||||
|
#=============================================================================
|
||||||
|
# imports
|
||||||
|
#=============================================================================
|
||||||
|
# core
|
||||||
|
import logging; log = logging.getLogger(__name__)
|
||||||
|
from itertools import chain
|
||||||
|
# site
|
||||||
|
# pkg
|
||||||
|
from passlib import hash
|
||||||
|
from passlib.context import LazyCryptContext
|
||||||
|
from passlib.utils import sys_bits
|
||||||
|
# local
|
||||||
|
__all__ = [
|
||||||
|
'custom_app_context',
|
||||||
|
'django_context',
|
||||||
|
'ldap_context', 'ldap_nocrypt_context',
|
||||||
|
'mysql_context', 'mysql4_context', 'mysql3_context',
|
||||||
|
'phpass_context',
|
||||||
|
'phpbb3_context',
|
||||||
|
'postgres_context',
|
||||||
|
]
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# master containing all identifiable hashes
|
||||||
|
#=============================================================================
|
||||||
|
def _load_master_config():
|
||||||
|
from passlib.registry import list_crypt_handlers
|
||||||
|
|
||||||
|
# get master list
|
||||||
|
schemes = list_crypt_handlers()
|
||||||
|
|
||||||
|
# exclude the ones we know have ambiguous or greedy identify() methods.
|
||||||
|
excluded = [
|
||||||
|
# frequently confused for eachother
|
||||||
|
'bigcrypt',
|
||||||
|
'crypt16',
|
||||||
|
|
||||||
|
# no good identifiers
|
||||||
|
'cisco_pix',
|
||||||
|
'cisco_type7',
|
||||||
|
'htdigest',
|
||||||
|
'mysql323',
|
||||||
|
'oracle10',
|
||||||
|
|
||||||
|
# all have same size
|
||||||
|
'lmhash',
|
||||||
|
'msdcc',
|
||||||
|
'msdcc2',
|
||||||
|
'nthash',
|
||||||
|
|
||||||
|
# plaintext handlers
|
||||||
|
'plaintext',
|
||||||
|
'ldap_plaintext',
|
||||||
|
|
||||||
|
# disabled handlers
|
||||||
|
'django_disabled',
|
||||||
|
'unix_disabled',
|
||||||
|
'unix_fallback',
|
||||||
|
]
|
||||||
|
for name in excluded:
|
||||||
|
schemes.remove(name)
|
||||||
|
|
||||||
|
# return config
|
||||||
|
return dict(schemes=schemes, default="sha256_crypt")
|
||||||
|
master_context = LazyCryptContext(onload=_load_master_config)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# for quickly bootstrapping new custom applications
|
||||||
|
#=============================================================================
|
||||||
|
custom_app_context = LazyCryptContext(
|
||||||
|
# choose some reasonbly strong schemes
|
||||||
|
schemes=["sha512_crypt", "sha256_crypt"],
|
||||||
|
|
||||||
|
# set some useful global options
|
||||||
|
default="sha256_crypt" if sys_bits < 64 else "sha512_crypt",
|
||||||
|
|
||||||
|
# set a good starting point for rounds selection
|
||||||
|
sha512_crypt__min_rounds = 535000,
|
||||||
|
sha256_crypt__min_rounds = 535000,
|
||||||
|
|
||||||
|
# if the admin user category is selected, make a much stronger hash,
|
||||||
|
admin__sha512_crypt__min_rounds = 1024000,
|
||||||
|
admin__sha256_crypt__min_rounds = 1024000,
|
||||||
|
)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# django
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 1.0
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
_django10_schemes = [
|
||||||
|
"django_salted_sha1",
|
||||||
|
"django_salted_md5",
|
||||||
|
"django_des_crypt",
|
||||||
|
"hex_md5",
|
||||||
|
"django_disabled",
|
||||||
|
]
|
||||||
|
|
||||||
|
django10_context = LazyCryptContext(
|
||||||
|
schemes=_django10_schemes,
|
||||||
|
default="django_salted_sha1",
|
||||||
|
deprecated=["hex_md5"],
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 1.4
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
_django14_schemes = [
|
||||||
|
"django_pbkdf2_sha256",
|
||||||
|
"django_pbkdf2_sha1",
|
||||||
|
"django_bcrypt"
|
||||||
|
] + _django10_schemes
|
||||||
|
|
||||||
|
django14_context = LazyCryptContext(
|
||||||
|
schemes=_django14_schemes,
|
||||||
|
deprecated=_django10_schemes,
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 1.6
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
_django16_schemes = list(_django14_schemes)
|
||||||
|
_django16_schemes.insert(1, "django_bcrypt_sha256")
|
||||||
|
django16_context = LazyCryptContext(
|
||||||
|
schemes=_django16_schemes,
|
||||||
|
deprecated=_django10_schemes,
|
||||||
|
)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 1.10
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
_django_110_schemes = [
|
||||||
|
"django_pbkdf2_sha256",
|
||||||
|
"django_pbkdf2_sha1",
|
||||||
|
"django_argon2",
|
||||||
|
"django_bcrypt",
|
||||||
|
"django_bcrypt_sha256",
|
||||||
|
"django_disabled",
|
||||||
|
]
|
||||||
|
django110_context = LazyCryptContext(schemes=_django_110_schemes)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# 2.1
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
_django21_schemes = list(_django_110_schemes)
|
||||||
|
_django21_schemes.remove("django_bcrypt")
|
||||||
|
django21_context = LazyCryptContext(schemes=_django21_schemes)
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
# latest
|
||||||
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
# this will always point to latest version in passlib
|
||||||
|
django_context = django21_context
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# ldap
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
#: standard ldap schemes
|
||||||
|
std_ldap_schemes = [
|
||||||
|
"ldap_salted_sha512",
|
||||||
|
"ldap_salted_sha256",
|
||||||
|
"ldap_salted_sha1",
|
||||||
|
"ldap_salted_md5",
|
||||||
|
"ldap_sha1",
|
||||||
|
"ldap_md5",
|
||||||
|
"ldap_plaintext",
|
||||||
|
]
|
||||||
|
|
||||||
|
# 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
|
||||||
|
def _iter_ldap_crypt_schemes():
|
||||||
|
from passlib.utils import unix_crypt_schemes
|
||||||
|
return ('ldap_' + name for name in unix_crypt_schemes)
|
||||||
|
|
||||||
|
def _iter_ldap_schemes():
|
||||||
|
"""helper which iterates over supported std 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
|
||||||
|
##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
|
||||||
|
#=============================================================================
|
||||||
|
mysql3_context = LazyCryptContext(["mysql323"])
|
||||||
|
mysql4_context = LazyCryptContext(["mysql41", "mysql323"], deprecated="mysql323")
|
||||||
|
mysql_context = mysql4_context # tracks latest mysql version supported
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# postgres
|
||||||
|
#=============================================================================
|
||||||
|
postgres_context = LazyCryptContext(["postgres_md5"])
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# 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'
|
||||||
|
return kwds
|
||||||
|
|
||||||
|
phpass_context = LazyCryptContext(
|
||||||
|
schemes=["bcrypt", "phpass", "bsdi_crypt"],
|
||||||
|
onload=_create_phpass_policy,
|
||||||
|
)
|
||||||
|
|
||||||
|
phpbb3_context = LazyCryptContext(["phpass"], phpass__ident="H")
|
||||||
|
|
||||||
|
# TODO: support the drupal phpass variants (see phpass homepage)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# 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+
|
||||||
|
roundup_context = roundup15_context = LazyCryptContext(
|
||||||
|
schemes=_std_roundup_schemes + [ "ldap_pbkdf2_sha1" ],
|
||||||
|
deprecated=_std_roundup_schemes,
|
||||||
|
default = "ldap_pbkdf2_sha1",
|
||||||
|
ldap_pbkdf2_sha1__default_rounds = 10000,
|
||||||
|
)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# eof
|
||||||
|
#=============================================================================
|
||||||
2637
venv/Lib/site-packages/passlib/context.py
Normal file
2637
venv/Lib/site-packages/passlib/context.py
Normal file
File diff suppressed because it is too large
Load Diff
397
venv/Lib/site-packages/passlib/exc.py
Normal file
397
venv/Lib/site-packages/passlib/exc.py
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
"""passlib.exc -- exceptions & warnings raised by passlib"""
|
||||||
|
#=============================================================================
|
||||||
|
# exceptions
|
||||||
|
#=============================================================================
|
||||||
|
class UnknownBackendError(ValueError):
|
||||||
|
"""
|
||||||
|
Error raised if multi-backend handler doesn't recognize backend name.
|
||||||
|
Inherits from :exc:`ValueError`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
"""
|
||||||
|
def __init__(self, hasher, backend):
|
||||||
|
self.hasher = hasher
|
||||||
|
self.backend = backend
|
||||||
|
message = "%s: unknown backend: %r" % (hasher.name, backend)
|
||||||
|
ValueError.__init__(self, message)
|
||||||
|
|
||||||
|
|
||||||
|
# XXX: add a PasslibRuntimeError as base for Missing/Internal/Security runtime errors?
|
||||||
|
|
||||||
|
|
||||||
|
class MissingBackendError(RuntimeError):
|
||||||
|
"""Error raised if multi-backend handler has no available backends;
|
||||||
|
or if specifically requested backend is not available.
|
||||||
|
|
||||||
|
:exc:`!MissingBackendError` derives
|
||||||
|
from :exc:`RuntimeError`, since it usually indicates
|
||||||
|
lack of an external library or OS feature.
|
||||||
|
This is primarily raised by handlers which depend on
|
||||||
|
external libraries (which is currently just
|
||||||
|
:class:`~passlib.hash.bcrypt`).
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class InternalBackendError(RuntimeError):
|
||||||
|
"""
|
||||||
|
Error raised if something unrecoverable goes wrong with backend call;
|
||||||
|
such as if ``crypt.crypt()`` returning a malformed hash.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7.3
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordValueError(ValueError):
|
||||||
|
"""
|
||||||
|
Error raised if a password can't be hashed / verified for various reasons.
|
||||||
|
This exception derives from the builtin :exc:`!ValueError`.
|
||||||
|
|
||||||
|
May be thrown directly when password violates internal invariants of hasher
|
||||||
|
(e.g. some don't support NULL characters). Hashers may also throw more specific subclasses,
|
||||||
|
such as :exc:`!PasswordSizeError`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7.3
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordSizeError(PasswordValueError):
|
||||||
|
"""
|
||||||
|
Error raised if a password exceeds the maximum size allowed
|
||||||
|
by Passlib (by default, 4096 characters); or if password exceeds
|
||||||
|
a hash-specific size limitation.
|
||||||
|
|
||||||
|
This exception derives from :exc:`PasswordValueError` (above).
|
||||||
|
|
||||||
|
Many password hash algorithms take proportionately larger amounts of time and/or
|
||||||
|
memory depending on the size of the password provided. This could present
|
||||||
|
a potential denial of service (DOS) situation if a maliciously large
|
||||||
|
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`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Applications wishing to use a different limit should set the
|
||||||
|
``PASSLIB_MAX_PASSWORD_SIZE`` environmental variable before
|
||||||
|
Passlib is loaded. The value can be any large positive integer.
|
||||||
|
|
||||||
|
.. attribute:: max_size
|
||||||
|
|
||||||
|
indicates the maximum allowed size.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
max_size = None
|
||||||
|
|
||||||
|
def __init__(self, max_size, msg=None):
|
||||||
|
self.max_size = max_size
|
||||||
|
if msg is None:
|
||||||
|
msg = "password exceeds maximum allowed size"
|
||||||
|
PasswordValueError.__init__(self, msg)
|
||||||
|
|
||||||
|
# this also prevents a glibc crypt segfault issue, detailed here ...
|
||||||
|
# http://www.openwall.com/lists/oss-security/2011/11/15/1
|
||||||
|
|
||||||
|
class PasswordTruncateError(PasswordSizeError):
|
||||||
|
"""
|
||||||
|
Error raised if password would be truncated by hash.
|
||||||
|
This derives from :exc:`PasswordSizeError` (above).
|
||||||
|
|
||||||
|
Hashers such as :class:`~passlib.hash.bcrypt` can be configured to raises
|
||||||
|
this error by setting ``truncate_error=True``.
|
||||||
|
|
||||||
|
.. attribute:: max_size
|
||||||
|
|
||||||
|
indicates the maximum allowed size.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cls, msg=None):
|
||||||
|
if msg is None:
|
||||||
|
msg = ("Password too long (%s truncates to %d characters)" %
|
||||||
|
(cls.name, cls.truncate_size))
|
||||||
|
PasswordSizeError.__init__(self, cls.truncate_size, msg)
|
||||||
|
|
||||||
|
|
||||||
|
class PasslibSecurityError(RuntimeError):
|
||||||
|
"""
|
||||||
|
Error raised if critical security issue is detected
|
||||||
|
(e.g. an attempt is made to use a vulnerable version of a bcrypt backend).
|
||||||
|
|
||||||
|
.. versionadded:: 1.6.3
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TokenError(ValueError):
|
||||||
|
"""
|
||||||
|
Base error raised by v:mod:`passlib.totp` when
|
||||||
|
a token can't be parsed / isn't valid / etc.
|
||||||
|
Derives from :exc:`!ValueError`.
|
||||||
|
|
||||||
|
Usually one of the more specific subclasses below will be raised:
|
||||||
|
|
||||||
|
* :class:`MalformedTokenError` -- invalid chars, too few digits
|
||||||
|
* :class:`InvalidTokenError` -- no match found
|
||||||
|
* :class:`UsedTokenError` -- match found, but token already used
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: default message to use if none provided -- subclasses may fill this in
|
||||||
|
_default_message = 'Token not acceptable'
|
||||||
|
|
||||||
|
def __init__(self, msg=None, *args, **kwds):
|
||||||
|
if msg is None:
|
||||||
|
msg = self._default_message
|
||||||
|
ValueError.__init__(self, msg, *args, **kwds)
|
||||||
|
|
||||||
|
|
||||||
|
class MalformedTokenError(TokenError):
|
||||||
|
"""
|
||||||
|
Error raised by :mod:`passlib.totp` when a token isn't formatted correctly
|
||||||
|
(contains invalid characters, wrong number of digits, etc)
|
||||||
|
"""
|
||||||
|
_default_message = "Unrecognized token"
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidTokenError(TokenError):
|
||||||
|
"""
|
||||||
|
Error raised by :mod:`passlib.totp` when a token is formatted correctly,
|
||||||
|
but doesn't match any tokens within valid range.
|
||||||
|
"""
|
||||||
|
_default_message = "Token did not match"
|
||||||
|
|
||||||
|
|
||||||
|
class UsedTokenError(TokenError):
|
||||||
|
"""
|
||||||
|
Error raised by :mod:`passlib.totp` if a token is reused.
|
||||||
|
Derives from :exc:`TokenError`.
|
||||||
|
|
||||||
|
.. autoattribute:: expire_time
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
"""
|
||||||
|
_default_message = "Token has already been used, please wait for another."
|
||||||
|
|
||||||
|
#: optional value indicating when current counter period will end,
|
||||||
|
#: and a new token can be generated.
|
||||||
|
expire_time = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwds):
|
||||||
|
self.expire_time = kwds.pop("expire_time", None)
|
||||||
|
TokenError.__init__(self, *args, **kwds)
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownHashError(ValueError):
|
||||||
|
"""
|
||||||
|
Error raised by :class:`~passlib.crypto.lookup_hash` if hash name is not recognized.
|
||||||
|
This exception derives from :exc:`!ValueError`.
|
||||||
|
|
||||||
|
As of version 1.7.3, this may also be raised if hash algorithm is known,
|
||||||
|
but has been disabled due to FIPS mode (message will include phrase "disabled for fips").
|
||||||
|
|
||||||
|
As of version 1.7.4, this may be raised if a :class:`~passlib.context.CryptContext`
|
||||||
|
is unable to identify the algorithm used by a password hash.
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
|
||||||
|
.. versionchanged: 1.7.3
|
||||||
|
added 'message' argument.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.7.4
|
||||||
|
altered call signature.
|
||||||
|
"""
|
||||||
|
def __init__(self, message=None, value=None):
|
||||||
|
self.value = value
|
||||||
|
if message is None:
|
||||||
|
message = "unknown hash algorithm: %r" % value
|
||||||
|
self.message = message
|
||||||
|
ValueError.__init__(self, message, value)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.message
|
||||||
|
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# warnings
|
||||||
|
#=============================================================================
|
||||||
|
class PasslibWarning(UserWarning):
|
||||||
|
"""base class for Passlib's user warnings,
|
||||||
|
derives from the builtin :exc:`UserWarning`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
# XXX: there's only one reference to this class, and it will go away in 2.0;
|
||||||
|
# so can probably remove this along with this / roll this into PasslibHashWarning.
|
||||||
|
class PasslibConfigWarning(PasslibWarning):
|
||||||
|
"""Warning issued when non-fatal issue is found related to the configuration
|
||||||
|
of a :class:`~passlib.context.CryptContext` instance.
|
||||||
|
|
||||||
|
This occurs primarily in one of two cases:
|
||||||
|
|
||||||
|
* The CryptContext contains rounds limits which exceed the hard limits
|
||||||
|
imposed by the underlying algorithm.
|
||||||
|
* An explicit rounds value was provided which exceeds the limits
|
||||||
|
imposed by the CryptContext.
|
||||||
|
|
||||||
|
In both of these cases, the code will perform correctly & securely;
|
||||||
|
but the warning is issued as a sign the configuration may need updating.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PasslibHashWarning(PasslibWarning):
|
||||||
|
"""Warning issued when non-fatal issue is found with parameters
|
||||||
|
or hash string passed to a passlib hash class.
|
||||||
|
|
||||||
|
This occurs primarily in one of two cases:
|
||||||
|
|
||||||
|
* A rounds value or other setting was explicitly provided which
|
||||||
|
exceeded the handler's limits (and has been clamped
|
||||||
|
by the :ref:`relaxed<relaxed-keyword>` flag).
|
||||||
|
|
||||||
|
* A malformed hash string was encountered which (while parsable)
|
||||||
|
should be re-encoded.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PasslibRuntimeWarning(PasslibWarning):
|
||||||
|
"""Warning issued when something unexpected happens during runtime.
|
||||||
|
|
||||||
|
The fact that it's a warning instead of an error means Passlib
|
||||||
|
was able to correct for the issue, but that it's anomalous enough
|
||||||
|
that the developers would love to hear under what conditions it occurred.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
class PasslibSecurityWarning(PasslibWarning):
|
||||||
|
"""Special warning issued when Passlib encounters something
|
||||||
|
that might affect security.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# error constructors
|
||||||
|
#
|
||||||
|
# note: these functions are used by the hashes in Passlib to raise common
|
||||||
|
# error messages. They are currently just functions which return ValueError,
|
||||||
|
# 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__
|
||||||
|
if cls.__module__ and cls.__module__ not in ["__builtin__", "builtins"]:
|
||||||
|
return "%s.%s" % (cls.__module__, cls.__name__)
|
||||||
|
elif value is None:
|
||||||
|
return 'None'
|
||||||
|
else:
|
||||||
|
return cls.__name__
|
||||||
|
|
||||||
|
def ExpectedTypeError(value, expected, param):
|
||||||
|
"""error message when param was supposed to be one type, but found another"""
|
||||||
|
# NOTE: value is never displayed, since it may sometimes be a password.
|
||||||
|
name = type_name(value)
|
||||||
|
return TypeError("%s must be %s, not %s" % (param, expected, name))
|
||||||
|
|
||||||
|
def ExpectedStringError(value, param):
|
||||||
|
"""error message when param was supposed to be unicode or bytes"""
|
||||||
|
return ExpectedTypeError(value, "unicode or bytes", param)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------
|
||||||
|
# hash/verify parameter errors
|
||||||
|
#------------------------------------------------------------------------
|
||||||
|
def MissingDigestError(handler=None):
|
||||||
|
"""raised when verify() method gets passed config string instead of hash"""
|
||||||
|
name = _get_name(handler)
|
||||||
|
return ValueError("expected %s hash, got %s config string instead" %
|
||||||
|
(name, name))
|
||||||
|
|
||||||
|
def NullPasswordError(handler=None):
|
||||||
|
"""raised by OS crypt() supporting hashes, which forbid NULLs in password"""
|
||||||
|
name = _get_name(handler)
|
||||||
|
return PasswordValueError("%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))
|
||||||
|
|
||||||
|
def MalformedHashError(handler=None, reason=None):
|
||||||
|
"""error raised if recognized-but-malformed hash provided to handler"""
|
||||||
|
text = "malformed %s hash" % _get_name(handler)
|
||||||
|
if reason:
|
||||||
|
text = "%s (%s)" % (text, reason)
|
||||||
|
return ValueError(text)
|
||||||
|
|
||||||
|
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,
|
||||||
|
# not from parsing a hash string, might want different error msg.
|
||||||
|
checksum_size = handler.checksum_size
|
||||||
|
unit = "bytes" if raw else "chars"
|
||||||
|
reason = "checksum must be exactly %d %s" % (checksum_size, unit)
|
||||||
|
return MalformedHashError(handler, reason)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# sensitive info helpers
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
#: global flag, set temporarily by UTs to allow debug_only_repr() to display sensitive values.
|
||||||
|
ENABLE_DEBUG_ONLY_REPR = False
|
||||||
|
|
||||||
|
|
||||||
|
def debug_only_repr(value, param="hash"):
|
||||||
|
"""
|
||||||
|
helper used to display sensitive data (hashes etc) within error messages.
|
||||||
|
currently returns placeholder test UNLESS unittests are running,
|
||||||
|
in which case the real value is displayed.
|
||||||
|
|
||||||
|
mainly useful to prevent hashes / secrets from being exposed in production tracebacks;
|
||||||
|
while still being visible from test failures.
|
||||||
|
|
||||||
|
NOTE: api subject to change, may formalize this more in the future.
|
||||||
|
"""
|
||||||
|
if ENABLE_DEBUG_ONLY_REPR or value is None or isinstance(value, bool):
|
||||||
|
return repr(value)
|
||||||
|
return "<%s %s value omitted>" % (param, type(value))
|
||||||
|
|
||||||
|
|
||||||
|
def CryptBackendError(handler, config, hash, # *
|
||||||
|
source="crypt.crypt()"):
|
||||||
|
"""
|
||||||
|
helper to generate standard message when ``crypt.crypt()`` returns invalid result.
|
||||||
|
takes care of automatically masking contents of config & hash outside of UTs.
|
||||||
|
"""
|
||||||
|
name = _get_name(handler)
|
||||||
|
msg = "%s returned invalid %s hash: config=%s hash=%s" % \
|
||||||
|
(source, name, debug_only_repr(config), debug_only_repr(hash))
|
||||||
|
raise InternalBackendError(msg)
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# eof
|
||||||
|
#=============================================================================
|
||||||
Reference in New Issue
Block a user