From 7d62a9fc8e966c2e657098b2de5fb1a6e577bdc5 Mon Sep 17 00:00:00 2001 From: Eli Collins Date: Wed, 1 Aug 2012 17:05:29 -0400 Subject: misc fixes * hash_needs_update() now issues deprecation warning. * deprecated_function decorator appends CR to docstring if needed. * rng genseed() fallback now gulps down a bunch more entropy --- passlib/context.py | 10 +++------- passlib/ext/django/models.py | 2 +- passlib/utils/__init__.py | 41 ++++++++++++++++++++++------------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/passlib/context.py b/passlib/context.py index 940954d..df338e2 100644 --- a/passlib/context.py +++ b/passlib/context.py @@ -18,7 +18,7 @@ from warnings import warn # 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, \ +from passlib.utils import rng, tick, to_bytes, deprecated_method, \ to_unicode, splitcomma from passlib.utils.compat import bytes, iteritems, num_types, \ PY2, PY3, PY_MIN_32, unicode, SafeConfigParser, \ @@ -2309,13 +2309,9 @@ class CryptContext(object): record = self._get_or_identify_record(hash, scheme, category) return record.needs_update(hash, secret) + @deprecated_method(deprecated="1.6", removed="1.8", replacement="CryptContext.needs_update()") def hash_needs_update(self, hash, scheme=None, category=None): - """legacy alias for :meth:`needs_update`. - - .. deprecated:: 1.6 - use :meth:`needs_update` instead. - """ - # FIXME: needs deprecation warning. + """legacy alias for :meth:`needs_update`""" return self.needs_update(hash, scheme, category) def genconfig(self, scheme=None, category=None, **settings): diff --git a/passlib/ext/django/models.py b/passlib/ext/django/models.py index 4fb6aea..b4a40da 100644 --- a/passlib/ext/django/models.py +++ b/passlib/ext/django/models.py @@ -240,7 +240,7 @@ def _load(): if config is _UNSET: config = "passlib-default" if config is None: - warn("PASSLIB_CONFIG=None is deprecated, " + warn("setting PASSLIB_CONFIG=None is deprecated, " "and support will be removed in Passlib 1.8, " "use PASSLIB_CONFIG='disabled' instead.", DeprecationWarning) diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index 3b3c9f0..aff0642 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -186,6 +186,8 @@ def deprecated_function(msg=None, deprecated=None, removed=None, updoc=True, txt += ", " txt += "use %s instead" % replacement txt += "." + if not wrapper.__doc__.strip(" ").endswith("\n"): + wrapper.__doc__ += "\n" wrapper.__doc__ += "\n.. deprecated:: %s\n" % (txt,) return wrapper return build @@ -295,12 +297,12 @@ def consteq(left, right): # NOTE: the double-if construction below is done deliberately, to ensure # the same number of operations (including branches) is performed regardless # of whether left & right are the same size. - same = (len(left) == len(right)) - if same: + same_size = (len(left) == len(right)) + if same_size: # if sizes are the same, setup loop to perform actual check of contents. tmp = left result = 0 - if not same: + if not same_size: # if sizes aren't the same, set 'result' so equality will fail regardless # of contents. then, to ensure we do exactly 'len(right)' iterations # of the loop, just compare 'right' against itself. @@ -1432,8 +1434,8 @@ else: # 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 +# that making a rainbow table is too costly. so it should be ok to +# fall back on python's builtin mersenne twister prng, as long as it's seeded each time # this module is imported, using a couple of minor entropy sources. try: @@ -1445,34 +1447,35 @@ except NotImplementedError: # pragma: no cover def genseed(value=None): "generate prng seed value from system resources" # if value is rng, extract a bunch of bits from it's state - from hashlib import sha256 + from hashlib import sha512 if hasattr(value, "getrandbits"): - value = value.getrandbits(256) - text = u("%s %s %s %.15f %s") % ( + value = value.getrandbits(1<<15) + text = u("%s %s %s %.15f %.15f %s") % ( + # if caller specified a seed value (e.g. current rng state), mix it in value, - # if user specified a seed value (e.g. current rng state), mix it in + # add current process id + # NOTE: not available in some environments, e.g. GAE os.getpid() if hasattr(os, "getpid") else None, - # add current process id - # NOTE: not available in some environments, e.g. GAE + # id of a freshly created object. + # (at least 1 byte of which should be hard to predict) id(object()), - # id of a freshly created object. - # (at least 2 bytes of which should be hard to predict) + # the current time, to whatever precision os uses time.time(), - # the current time, to whatever precision os uses + time.clock(), - 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. + os.urandom(32).decode("latin-1") if has_urandom else 0, ) # hash it all up and return it as int/long - return int(sha256(text.encode("utf-8")).hexdigest(), 16) + return int(sha512(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 -- runtime detection + # NOTE: to reseed use ``rng.seed(genseed(rng))`` rng = random.Random(genseed()) #------------------------------------------------------------------------ -- cgit v1.2.1