diff options
Diffstat (limited to 'passlib/utils')
-rw-r--r-- | passlib/utils/__init__.py | 117 | ||||
-rw-r--r-- | passlib/utils/compat.py | 10 | ||||
-rw-r--r-- | passlib/utils/handlers.py | 22 | ||||
-rw-r--r-- | passlib/utils/md4.py | 6 |
4 files changed, 73 insertions, 82 deletions
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index e0b9e75..9eb8eab 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -162,50 +162,50 @@ def deprecated_function(msg=None, deprecated=None, removed=None, updoc=True): return wrapper return build -def relocated_function(target, msg=None, name=None, deprecated=None, mod=None, - removed=None, updoc=True): - """constructor to create alias for relocated function. - - :arg target: import path to target - :arg msg: optional msg, default chosen if omitted - :kwd deprecated: release where function was first deprecated - :kwd removed: release where function will be removed - :kwd updoc: add notice to docstring (default ``True``) - """ - target_mod, target_name = target.rsplit(".",1) - if mod is None: - import inspect - mod = inspect.currentframe(1).f_globals["__name__"] - if not name: - name = target_name - if msg is None: - msg = ("the function %(mod)s.%(name)s() has been moved to " - "%(target_mod)s.%(target_name)s(), the old location is deprecated") - if deprecated: - msg += " as of Passlib %(deprecated)s" - if removed: - msg += ", and will be removed in Passlib %(removed)s" - msg += "." - msg %= dict( - mod=mod, - name=name, - target_mod=target_mod, - target_name=target_name, - deprecated=deprecated, - removed=removed, - ) - state = [None] - def wrapper(*args, **kwds): - warn(msg, DeprecationWarning, stacklevel=2) - func = state[0] - if func is None: - module = __import__(target_mod, fromlist=[target_name], level=0) - func = state[0] = getattr(module, target_name) - return func(*args, **kwds) - wrapper.__module__ = mod - wrapper.__name__ = name - wrapper.__doc__ = msg - return wrapper +##def relocated_function(target, msg=None, name=None, deprecated=None, mod=None, +## removed=None, updoc=True): +## """constructor to create alias for relocated function. +## +## :arg target: import path to target +## :arg msg: optional msg, default chosen if omitted +## :kwd deprecated: release where function was first deprecated +## :kwd removed: release where function will be removed +## :kwd updoc: add notice to docstring (default ``True``) +## """ +## target_mod, target_name = target.rsplit(".",1) +## if mod is None: +## import inspect +## mod = inspect.currentframe(1).f_globals["__name__"] +## if not name: +## name = target_name +## if msg is None: +## msg = ("the function %(mod)s.%(name)s() has been moved to " +## "%(target_mod)s.%(target_name)s(), the old location is deprecated") +## if deprecated: +## msg += " as of Passlib %(deprecated)s" +## if removed: +## msg += ", and will be removed in Passlib %(removed)s" +## msg += "." +## msg %= dict( +## mod=mod, +## name=name, +## target_mod=target_mod, +## target_name=target_name, +## deprecated=deprecated, +## removed=removed, +## ) +## state = [None] +## def wrapper(*args, **kwds): +## warn(msg, DeprecationWarning, stacklevel=2) +## func = state[0] +## if func is None: +## module = __import__(target_mod, fromlist=[target_name], level=0) +## func = state[0] = getattr(module, target_name) +## return func(*args, **kwds) +## wrapper.__module__ = mod +## wrapper.__name__ = name +## wrapper.__doc__ = msg +## return wrapper class memoized_property(object): """decorator which invokes method once, then replaces attr with result""" @@ -309,7 +309,7 @@ def consteq(left, right): return result == 0 @deprecated_function(deprecated="1.6", removed="1.8") -def splitcomma(source, sep=","): +def splitcomma(source, sep=","): # pragma: no cover """split comma-separated string into list of elements, stripping whitespace and discarding empty elements. """ @@ -465,7 +465,7 @@ def render_bytes(source, *args): # NOTE: deprecating bytes<->int in favor of just using struct module. @deprecated_function(deprecated="1.6", removed="1.8") -def bytes_to_int(value): +def bytes_to_int(value): # pragma: no cover "decode string of bytes as single big-endian integer" from passlib.utils.compat import byte_elem_value out = 0 @@ -474,7 +474,7 @@ def bytes_to_int(value): return out @deprecated_function(deprecated="1.6", removed="1.8") -def int_to_bytes(value, count): +def int_to_bytes(value, count): # pragma: no cover "encodes integer into single big-endian byte string" assert value < (1<<(8*count)), "value too large for %d bytes: %d" % (count, value) return join_byte_values( @@ -577,10 +577,10 @@ def to_unicode(source, source_encoding="utf-8", errname="value"): * returns unicode strings unchanged. * returns bytes strings decoded using *source_encoding* """ + assert source_encoding if isinstance(source, unicode): return source elif isinstance(source, bytes): - assert source_encoding return source.decode(source_encoding) else: raise ExpectedStringError(source, errname) @@ -624,7 +624,7 @@ add_doc(to_native_str, """) @deprecated_function(deprecated="1.6", removed="1.7") -def to_hash_str(source, encoding="ascii"): +def to_hash_str(source, encoding="ascii"): # pragma: no cover "deprecated, use to_native_str() instead" return to_native_str(source, encoding, errname="hash") @@ -698,7 +698,7 @@ class Base64Engine(object): if isinstance(charmap, unicode): charmap = charmap.encode("latin-1") elif not isinstance(charmap, bytes): - raise TypeError("charmap must be unicode/bytes string") + raise ExpectedStringError(charmap, "charmap") if len(charmap) != 64: raise ValueError("charmap must be 64 characters in length") if len(set(charmap)) != 64: @@ -1145,8 +1145,7 @@ class Base64Engine(object): :returns: a string of length ``int(ceil(bits/6.0))``. """ - if value < 0: - raise ValueError("value cannot be negative") + assert value >= 0, "caller did not sanitize input" pad = -bits % 6 bits += pad if self.big: @@ -1298,22 +1297,14 @@ else: if isinstance(secret, bytes): # Python 3's crypt() only accepts unicode, which is then # encoding using utf-8 before passing to the C-level crypt(). - # so we have to decode the secret, but also check that it - # re-encodes to the original sequence of bytes... otherwise - # the call to crypt() will digest the wrong value. + # so we have to decode the secret. orig = secret try: secret = secret.decode("utf-8") except UnicodeDecodeError: return None - if secret.encode("utf-8") != orig: - # just in case original encoding wouldn't be reproduced - # during call to os_crypt. not sure if/how this could - # happen, but being paranoid. - from passlib.exc import PasslibRuntimeWarning - warn("utf-8 password didn't re-encode correctly!", - PasslibRuntimeWarning) - return None + assert secret.encode("utf-8") == orig, \ + "utf-8 spec says this can't happen!" if _NULL in secret: raise ValueError("null character in secret") if isinstance(hash, bytes): diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py index 7bffb15..77f9c3c 100644 --- a/passlib/utils/compat.py +++ b/passlib/utils/compat.py @@ -34,7 +34,7 @@ __all__ = [ 'print_', # type detection - 'is_mapping', +## 'is_mapping', 'callable', 'int_types', 'num_types', @@ -234,9 +234,9 @@ else: #============================================================================= # typing #============================================================================= -def is_mapping(obj): - # non-exhaustive check, enough to distinguish from lists, etc - return hasattr(obj, "items") +##def is_mapping(obj): +## # non-exhaustive check, enough to distinguish from lists, etc +## return hasattr(obj, "items") if (3,0) <= sys.version_info < (3,2): # callable isn't dead, it's just resting @@ -390,7 +390,7 @@ class _LazyOverlayModule(ModuleType): attrs.update(self.__dict__) attrs.update(self.__attrmap) proxy = self.__proxy - if proxy: + if proxy is not None: attrs.update(dir(proxy)) return list(attrs) diff --git a/passlib/utils/handlers.py b/passlib/utils/handlers.py index fbf7b69..47e83b0 100644 --- a/passlib/utils/handlers.py +++ b/passlib/utils/handlers.py @@ -19,11 +19,11 @@ from passlib.exc import MissingBackendError, PasslibConfigWarning, \ from passlib.registry import get_crypt_handler from passlib.utils import classproperty, consteq, getrandstr, getrandbytes,\ BASE64_CHARS, HASH64_CHARS, rng, to_native_str, \ - is_crypt_handler, deprecated_function, to_unicode, \ + is_crypt_handler, to_unicode, \ MAX_PASSWORD_SIZE from passlib.utils.compat import b, join_byte_values, bytes, irange, u, \ uascii_to_str, join_unicode, unicode, str_to_uascii, \ - join_unicode, base_string_types + join_unicode, base_string_types, PY2 # local __all__ = [ # helpers for implementing MCF handlers @@ -173,7 +173,7 @@ def parse_mc3(hash, prefix, sep=_UDOLLAR, rounds_base=10, elif rounds: rounds = int(rounds, rounds_base) elif default_rounds is None: - raise exc.MalformedHashError(handler, "missing rounds field") + raise exc.MalformedHashError(handler, "empty rounds field") else: rounds = default_rounds @@ -411,15 +411,15 @@ class GenericHandler(object): # NOTE: no clear route to reasonbly convert unicode -> raw bytes, # so relaxed does nothing here if not isinstance(checksum, bytes): - raise TypeError("checksum must be byte string") + raise exc.ExpectedTypeError(checksum, "bytes", "checksum") elif not isinstance(checksum, unicode): - if self.relaxed: + if isinstance(checksum, bytes) and self.relaxed: warn("checksum should be unicode, not bytes", PasslibHashWarning) checksum = checksum.decode("ascii") else: - raise TypeError("checksum must be unicode string") + raise exc.ExpectedTypeError(checksum, "unicode", "checksum") # handle stub if checksum == self._stub_checksum: @@ -960,14 +960,14 @@ class HasSalt(GenericHandler): # check type if self._salt_is_bytes: if not isinstance(salt, bytes): - raise TypeError("salt must be specified as bytes") + raise exc.ExpectedTypeError(salt, "bytes", "salt") else: if not isinstance(salt, unicode): - # XXX: should we disallow bytes here? - if isinstance(salt, bytes): + # NOTE: allowing bytes under py2 so salt can be native str. + if isinstance(salt, bytes) and (PY2 or self.relaxed): salt = salt.decode("ascii") else: - raise TypeError("salt must be specified as unicode") + raise exc.ExpectedTypeError(salt, "unicode", "salt") # check charset sc = self.salt_chars @@ -1139,7 +1139,7 @@ class HasRounds(GenericHandler): # check type if not isinstance(rounds, int): - raise TypeError("rounds must be an integer") + raise exc.ExpectedTypeError(rounds, "integer", "rounds") # check bounds mn = self.min_rounds diff --git a/passlib/utils/md4.py b/passlib/utils/md4.py index cd3d012..4389a09 100644 --- a/passlib/utils/md4.py +++ b/passlib/utils/md4.py @@ -242,14 +242,14 @@ def _has_native_md4(): try: h = hashlib.new("md4") except ValueError: - #not supported + # not supported - ssl probably missing (e.g. ironpython) return False result = h.hexdigest() if result == '31d6cfe0d16ae931b73c59d7e0c089c0': return True if PYPY and result == '': - #as of 1.5, pypy md4 just returns null! - #since this is expected, don't bother w/ warning. + # as of pypy 1.5-1.7, this returns empty string! + # since this is expected, don't bother w/ warning. return False #anything else should alert user from passlib.exc import PasslibRuntimeWarning |