summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-01-18 17:51:32 -0500
committerEli Collins <elic@assurancetechnologies.com>2012-01-18 17:51:32 -0500
commit666aa14bf15ed898472463d2ec890de0b8c60923 (patch)
treef4ad79fb817cdca19e64dbb1abfe86c1a2c8ffc1 /passlib
parentb6d904be92c77bce061c78034145958401bba381 (diff)
downloadpasslib-666aa14bf15ed898472463d2ec890de0b8c60923.tar.gz
import cleanups
* moved bytes compat functions from utils to utils.compat (bord, bjoin, bjoin_ints, bjoin_elems, ujoin) * renamed bord -> belem_ord for clarify * a bunch of to_native_str() always use ascii, and have fixed input types (always bytes or always unicode). these don't need overhead of to_native_str(), so replaced those calls with two new funcs: compat.bascii_to_str() / compat.uascii_to_str() * cleaned up a lot of imports from utils/utils.compat to pull from correct module * simplified the to_string() logic of a bunch of handlers to reduce unicode<->byte transitions
Diffstat (limited to 'passlib')
-rw-r--r--passlib/apache.py5
-rw-r--r--passlib/context.py11
-rw-r--r--passlib/ext/django/models.py4
-rw-r--r--passlib/ext/django/utils.py4
-rw-r--r--passlib/handlers/bcrypt.py9
-rw-r--r--passlib/handlers/des_crypt.py17
-rw-r--r--passlib/handlers/digests.py7
-rw-r--r--passlib/handlers/django.py11
-rw-r--r--passlib/handlers/fshp.py11
-rw-r--r--passlib/handlers/ldap_digests.py9
-rw-r--r--passlib/handlers/md5_crypt.py6
-rw-r--r--passlib/handlers/misc.py7
-rw-r--r--passlib/handlers/mysql.py15
-rw-r--r--passlib/handlers/nthash.py9
-rw-r--r--passlib/handlers/oracle.py18
-rw-r--r--passlib/handlers/pbkdf2.py27
-rw-r--r--passlib/handlers/phpass.py7
-rw-r--r--passlib/handlers/postgres.py8
-rw-r--r--passlib/handlers/roundup.py2
-rw-r--r--passlib/handlers/scram.py17
-rw-r--r--passlib/handlers/sha1_crypt.py13
-rw-r--r--passlib/handlers/sha2_crypt.py13
-rw-r--r--passlib/handlers/sun_md5_crypt.py16
-rw-r--r--passlib/tests/test_context.py2
-rw-r--r--passlib/tests/test_utils.py44
-rw-r--r--passlib/tests/test_utils_handlers.py22
-rw-r--r--passlib/tests/utils.py28
-rw-r--r--passlib/utils/__init__.py73
-rw-r--r--passlib/utils/_blowfish/__init__.py5
-rw-r--r--passlib/utils/compat.py115
-rw-r--r--passlib/utils/des.py5
-rw-r--r--passlib/utils/handlers.py16
-rw-r--r--passlib/utils/md4.py6
-rw-r--r--passlib/utils/pbkdf2.py5
-rw-r--r--passlib/win32.py3
35 files changed, 291 insertions, 279 deletions
diff --git a/passlib/apache.py b/passlib/apache.py
index f34d1d0..ecde0ba 100644
--- a/passlib/apache.py
+++ b/passlib/apache.py
@@ -11,9 +11,8 @@ import sys
#site
#libs
from passlib.context import CryptContext
-from passlib.utils import render_bytes, bjoin, bytes, b, \
- to_unicode, to_bytes, consteq
-from passlib.utils.compat import lmap, unicode, u
+from passlib.utils import consteq, render_bytes
+from passlib.utils.compat import b, bytes, bjoin, lmap, u, unicode
#pkg
#local
__all__ = [
diff --git a/passlib/context.py b/passlib/context.py
index 7b99a26..6466903 100644
--- a/passlib/context.py
+++ b/passlib/context.py
@@ -22,12 +22,11 @@ except ImportError:
resource_string = None
#libs
from passlib.registry import get_crypt_handler, _validate_handler_name
-from passlib.utils import to_bytes, to_unicode, bytes, \
- is_crypt_handler, rng, \
- PasslibPolicyWarning, tick, saslprep
-from passlib.utils.compat import is_mapping, iteritems, num_types, \
- PY3, PY_MIN_32, unicode, bytes
-from passlib.utils.compat.aliases import SafeConfigParser, StringIO, BytesIO
+from passlib.utils import is_crypt_handler, rng, saslprep, tick, to_bytes, \
+ to_unicode, PasslibPolicyWarning
+from passlib.utils.compat import bytes, is_mapping, iteritems, num_types, \
+ PY3, PY_MIN_32, unicode, SafeConfigParser, \
+ StringIO, BytesIO
#pkg
#local
__all__ = [
diff --git a/passlib/ext/django/models.py b/passlib/ext/django/models.py
index b86a796..9ae17b7 100644
--- a/passlib/ext/django/models.py
+++ b/passlib/ext/django/models.py
@@ -15,8 +15,8 @@ see the Passlib documentation for details on how to use this app
from django.conf import settings
#pkg
from passlib.context import CryptContext, CryptPolicy
-from passlib.utils import is_crypt_context, bytes
-from passlib.utils.compat import sb_types, unicode
+from passlib.utils import is_crypt_context
+from passlib.utils.compat import bytes, sb_types, unicode
from passlib.ext.django.utils import DEFAULT_CTX, get_category, \
set_django_password_context
diff --git a/passlib/ext/django/utils.py b/passlib/ext/django/utils.py
index dbd3581..fc7c713 100644
--- a/passlib/ext/django/utils.py
+++ b/passlib/ext/django/utils.py
@@ -12,8 +12,8 @@
#site
from warnings import warn
#pkg
-from passlib.utils import is_crypt_context, bytes
-from passlib.utils.compat import get_method_function as um
+from passlib.utils import is_crypt_context
+from passlib.utils.compat import bytes, get_method_function as um
#local
__all__ = [
"get_category",
diff --git a/passlib/handlers/bcrypt.py b/passlib/handlers/bcrypt.py
index f651dd0..8c1a1d8 100644
--- a/passlib/handlers/bcrypt.py
+++ b/passlib/handlers/bcrypt.py
@@ -16,7 +16,6 @@ import os
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
-from passlib.utils.compat import u
#site
try:
from bcrypt import hashpw as pybcrypt_hashpw
@@ -27,9 +26,9 @@ try:
except ImportError: #pragma: no cover - though should run whole suite w/o bcryptor installed
bcryptor_engine = None
#libs
-from passlib.utils import safe_os_crypt, classproperty, handlers as uh, \
- h64, to_native_str, rng, getrandstr, bytes, BCRYPT_CHARS as BCHARS
-from passlib.utils.compat import unicode
+from passlib.utils import safe_os_crypt, classproperty, rng, getrandstr
+from passlib.utils.compat import bytes, u, uascii_to_str, unicode
+import passlib.utils.handlers as uh
#pkg
#local
@@ -145,7 +144,7 @@ class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.
def to_string(self, native=True):
hash = u("%s%02d$%s%s") % (self.ident, self.rounds, self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
# specialized salt generation - fixes passlib issue 25
diff --git a/passlib/handlers/des_crypt.py b/passlib/handlers/des_crypt.py
index 1669ac8..da64560 100644
--- a/passlib/handlers/des_crypt.py
+++ b/passlib/handlers/des_crypt.py
@@ -58,11 +58,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, classproperty, safe_os_crypt, b, bytes, \
- to_native_str, handlers as uh, bord
-from passlib.utils.compat import unicode
+from passlib.utils import classproperty, h64, h64big, safe_os_crypt
+from passlib.utils.compat import b, bytes, belem_ord, u, uascii_to_str, unicode
from passlib.utils.des import mdes_encrypt_int_block
-from passlib.utils.compat import u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -78,7 +77,7 @@ __all__ = [
def _crypt_secret_to_key(secret):
"crypt helper which converts lower 7 bits of first 8 chars of secret -> 56-bit des key, padded to 64 bits"
return sum(
- (bord(c) & 0x7f) << (57-8*i)
+ (belem_ord(c) & 0x7f) << (57-8*i)
for i, c in enumerate(secret[:8])
)
@@ -196,7 +195,7 @@ class des_crypt(uh.HasManyBackends, uh.HasSalt, uh.GenericHandler):
def to_string(self, native=True):
hash = u("%s%s") % (self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
@@ -325,7 +324,7 @@ class bsdi_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
def to_string(self, native=True):
hash = u("_%s%s%s") % (h64.encode_int24(self.rounds).decode("ascii"),
self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
@@ -417,7 +416,7 @@ class bigcrypt(uh.HasSalt, uh.GenericHandler):
def to_string(self, native=True):
hash = u("%s%s") % (self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
@classmethod
def norm_checksum(cls, value, strict=False):
@@ -502,7 +501,7 @@ class crypt16(uh.HasSalt, uh.GenericHandler):
def to_string(self, native=True):
hash = u("%s%s") % (self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
diff --git a/passlib/handlers/digests.py b/passlib/handlers/digests.py
index e3c5a64..34e1dd3 100644
--- a/passlib/handlers/digests.py
+++ b/passlib/handlers/digests.py
@@ -9,8 +9,9 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import handlers as uh, to_native_str, bytes
-from passlib.utils.compat import unicode
+from passlib.utils import to_native_str
+from passlib.utils.compat import bascii_to_str, bytes, unicode
+import passlib.utils.handlers as uh
from passlib.utils.md4 import md4
#pkg
#local
@@ -52,7 +53,7 @@ class HexDigestHash(uh.StaticHandler):
raise TypeError("no secret provided")
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
- return to_native_str(cls._hash_func(secret).hexdigest())
+ return bascii_to_str(cls._hash_func(secret).hexdigest())
@classmethod
def _norm_hash(cls, hash):
diff --git a/passlib/handlers/django.py b/passlib/handlers/django.py
index e407814..2c4452b 100644
--- a/passlib/handlers/django.py
+++ b/passlib/handlers/django.py
@@ -9,8 +9,9 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, handlers as uh, b, bytes, to_unicode, to_native_str
-from passlib.utils.compat import unicode, u
+from passlib.utils import to_unicode
+from passlib.utils.compat import b, bytes, uascii_to_str, unicode, u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -65,8 +66,8 @@ class DjangoSaltedHash(uh.HasStubChecksum, uh.HasSalt, uh.GenericHandler):
def to_string(self):
chk = self.checksum or self._stub_checksum
- out = u("%s%s$%s") % (self.ident, self.salt, chk)
- return to_native_str(out)
+ hash = u("%s%s$%s") % (self.ident, self.salt, chk)
+ return uascii_to_str(hash)
class django_salted_sha1(DjangoSaltedHash):
"""This class implements Django's Salted SHA1 hash, and follows the :ref:`password-hash-api`.
@@ -210,7 +211,7 @@ class django_disabled(uh.StaticHandler):
def genhash(cls, secret, config):
if secret is None:
raise TypeError("no secret provided")
- return to_native_str(u("!"))
+ return "!"
@classmethod
def verify(cls, secret, hash):
diff --git a/passlib/handlers/fshp.py b/passlib/handlers/fshp.py
index 67c4ee1..424bf09 100644
--- a/passlib/handlers/fshp.py
+++ b/passlib/handlers/fshp.py
@@ -11,10 +11,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import handlers as uh, bytes, b, to_native_str
-from passlib.utils.compat import iteritems, 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
-from passlib.utils.compat import u
#pkg
#local
__all__ = [
@@ -164,9 +164,8 @@ class fshp(uh.HasStubChecksum, uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, u
def to_string(self):
chk = self.checksum or self._stub_checksum
salt = self.salt
- data = b64encode(salt+chk).decode("ascii")
- hash = u("{FSHP%d|%d|%d}%s") % (self.variant, len(salt), self.rounds, data)
- return to_native_str(hash)
+ data = bascii_to_str(b64encode(salt+chk))
+ return "{FSHP%d|%d|%d}%s" % (self.variant, len(salt), self.rounds, data)
#=========================================================
#backend
diff --git a/passlib/handlers/ldap_digests.py b/passlib/handlers/ldap_digests.py
index 2f6606d..8393be5 100644
--- a/passlib/handlers/ldap_digests.py
+++ b/passlib/handlers/ldap_digests.py
@@ -11,8 +11,9 @@ import re
from warnings import warn
#site
#libs
-from passlib.utils import handlers as uh, unix_crypt_schemes, b, bytes, to_native_str
-from passlib.utils.compat import unicode, u
+from passlib.utils import to_native_str, unix_crypt_schemes
+from passlib.utils.compat import b, bytes, uascii_to_str, unicode, u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -60,7 +61,7 @@ class _Base64DigestHelper(uh.StaticHandler):
raise ValueError("not a %s hash" % (cls.name,))
chk = cls._hash_func(secret).digest()
hash = cls.ident + b64encode(chk).decode("ascii")
- return to_native_str(hash)
+ return uascii_to_str(hash)
class _SaltedBase64DigestHelper(uh.HasStubChecksum, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
"helper for ldap_salted_md5 / ldap_salted_sha1"
@@ -93,7 +94,7 @@ class _SaltedBase64DigestHelper(uh.HasStubChecksum, uh.HasRawSalt, uh.HasRawChec
def to_string(self):
data = (self.checksum or self._stub_checksum) + self.salt
hash = self.ident + b64encode(data).decode("ascii")
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
if secret is None:
diff --git a/passlib/handlers/md5_crypt.py b/passlib/handlers/md5_crypt.py
index 66641f7..2dd9e7e 100644
--- a/passlib/handlers/md5_crypt.py
+++ b/passlib/handlers/md5_crypt.py
@@ -9,9 +9,9 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import b, bytes, to_bytes, h64, safe_os_crypt, \
- classproperty, handlers as uh
-from passlib.utils.compat import irange, unicode, u
+from passlib.utils import classproperty, h64, safe_os_crypt
+from passlib.utils.compat import b, bytes, irange, unicode, u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
diff --git a/passlib/handlers/misc.py b/passlib/handlers/misc.py
index 948b851..7233768 100644
--- a/passlib/handlers/misc.py
+++ b/passlib/handlers/misc.py
@@ -8,7 +8,9 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import to_native_str, handlers as uh, bytes
+from passlib.utils import to_native_str
+from passlib.utils.compat import bytes, unicode
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -47,7 +49,8 @@ class unix_fallback(uh.StaticHandler):
raise TypeError("secret must be string")
if hash is None:
raise ValueError("no hash provided")
- return to_native_str(hash)
+ # NOTE: hash will generally be "!"
+ return to_native_str(hash, "ascii", errname="hash")
@classmethod
def verify(cls, secret, hash, enable_wildcard=False):
diff --git a/passlib/handlers/mysql.py b/passlib/handlers/mysql.py
index 9705b9d..f8d9cf1 100644
--- a/passlib/handlers/mysql.py
+++ b/passlib/handlers/mysql.py
@@ -30,8 +30,9 @@ from warnings import warn
#site
#libs
#pkg
-from passlib.utils import handlers as uh, to_native_str, b, bord, bytes
-from passlib.utils.compat import unicode, u
+from passlib.utils import to_native_str
+from passlib.utils.compat import b, bytes, unicode, u, belem_ord
+import passlib.utils.handlers as uh
#local
__all__ = [
'mysql323',
@@ -82,12 +83,11 @@ class mysql323(uh.StaticHandler):
for c in secret:
if c in b(' \t'):
continue
- tmp = bord(c)
+ tmp = belem_ord(c)
nr1 ^= ((((nr1 & 63)+add)*tmp) + (nr1 << 8)) & MASK_32
nr2 = (nr2+((nr2 << 8) ^ nr1)) & MASK_32
add = (add+tmp) & MASK_32
- hash = u("%08x%08x") % (nr1 & MASK_31, nr2 & MASK_31)
- return to_native_str(hash)
+ return "%08x%08x" % (nr1 & MASK_31, nr2 & MASK_31)
@classmethod
def _norm_hash(cls, hash):
@@ -127,10 +127,11 @@ class mysql41(uh.StaticHandler):
def genhash(cls, secret, config):
if config is not None and not cls.identify(config):
raise ValueError("not a mysql-4.1 hash")
- #FIXME: no idea if mysql has a policy about handling unicode passwords
+ # FIXME: no idea if mysql has a policy about handling unicode passwords
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
- return '*' + sha1(sha1(secret).digest()).hexdigest().upper()
+ chk = bascii_to_str(sha1(sha1(secret).digest()).hexdigest())
+ return '*' + chk.upper()
@classmethod
def _norm_hash(cls, hash):
diff --git a/passlib/handlers/nthash.py b/passlib/handlers/nthash.py
index 03340a9..1576a32 100644
--- a/passlib/handlers/nthash.py
+++ b/passlib/handlers/nthash.py
@@ -8,9 +8,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import handlers as uh, to_unicode, to_native_str, to_bytes, bytes
+from passlib.utils import to_unicode
+from passlib.utils.compat import bytes, u, uascii_to_str
from passlib.utils.md4 import md4
-from passlib.utils.compat import u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -69,7 +70,7 @@ class nthash(uh.HasStubChecksum, uh.HasManyIdents, uh.GenericHandler):
def to_string(self):
hash = self.ident + (self.checksum or self._stub_checksum)
- return to_native_str(hash)
+ return uascii_to_str(hash)
#=========================================================
#primary interface
@@ -86,7 +87,7 @@ class nthash(uh.HasStubChecksum, uh.HasManyIdents, uh.GenericHandler):
returns string of raw bytes if ``hex=False``,
returns digest as hexidecimal unicode if ``hex=True``.
"""
- secret = to_unicode(secret, "utf-8")
+ secret = to_unicode(secret, "utf-8", errname="secret")
hash = md4(secret.encode("utf-16le"))
if hex:
return to_unicode(hash.hexdigest(), 'ascii')
diff --git a/passlib/handlers/oracle.py b/passlib/handlers/oracle.py
index f8fdc25..e0c6ff2 100644
--- a/passlib/handlers/oracle.py
+++ b/passlib/handlers/oracle.py
@@ -11,11 +11,11 @@ from warnings import warn
#site
#libs
#pkg
-from passlib.utils import xor_bytes, handlers as uh, bytes, to_unicode, \
- to_native_str, b
-from passlib.utils.compat import irange, unicode
+from passlib.utils import to_unicode, to_native_str, xor_bytes
+from passlib.utils.compat import bytes, bascii_to_str, irange, u, \
+ uascii_to_str, unicode
from passlib.utils.des import des_encrypt_block
-from passlib.utils.compat import u
+import passlib.utils.handlers as uh
#local
__all__ = [
"oracle10g",
@@ -104,18 +104,18 @@ class oracle10(uh.StaticHandler):
# this whole mess really needs someone w/ an oracle system,
# and some answers :)
- def encode(value):
+ def encode(value, errname):
"encode according to guess at how oracle encodes strings (see note above)"
#we can't trust what original encoding was.
#user should have passed us unicode in the first place.
#but try decoding as utf-8 just to work for most common case.
- value = to_unicode(value, "utf-8")
+ value = to_unicode(value, "utf-8", errname=errname)
return value.upper().encode("utf-16-be")
- input = encode(user) + encode(secret)
+ input = encode(user, 'user') + encode(secret, 'secret')
hash = des_cbc_encrypt(ORACLE10_MAGIC, input)
hash = des_cbc_encrypt(hash, input)
- return to_native_str(hexlify(hash)).upper()
+ return bascii_to_str(hexlify(hash)).upper()
@classmethod
def _norm_hash(cls, hash):
@@ -182,7 +182,7 @@ class oracle11(uh.HasStubChecksum, uh.HasSalt, uh.GenericHandler):
def to_string(self):
chk = (self.checksum or self._stub_checksum)
hash = u("S:%s%s") % (chk.upper(), self.salt.upper())
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
if isinstance(secret, unicode):
diff --git a/passlib/handlers/pbkdf2.py b/passlib/handlers/pbkdf2.py
index 889f511..748d75d 100644
--- a/passlib/handlers/pbkdf2.py
+++ b/passlib/handlers/pbkdf2.py
@@ -10,11 +10,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import ab64_encode, ab64_decode, \
- handlers as uh, to_native_str, to_unicode, bytes, b
-from passlib.utils.compat import unicode
+from passlib.utils import ab64_decode, ab64_encode
+from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode
from passlib.utils.pbkdf2 import pbkdf2
-from passlib.utils.compat import u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -88,7 +87,7 @@ class Pbkdf2DigestHandler(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gen
hash = u('%s%d$%s$%s') % (self.ident, self.rounds, salt, chk)
else:
hash = u('%s%d$%s') % (self.ident, self.rounds, salt)
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
if isinstance(secret, unicode):
@@ -222,12 +221,12 @@ class cta_pbkdf2_sha1(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Generic
)
def to_string(self, withchk=True):
- out = u('$p5k2$%x$%s') % (self.rounds,
+ hash = u('$p5k2$%x$%s') % (self.rounds,
b64encode(self.salt, CTA_ALTCHARS).decode("ascii"))
if withchk and self.checksum:
- out = u("%s$%s") % (out,
+ hash = u("%s$%s") % (hash,
b64encode(self.checksum, CTA_ALTCHARS).decode("ascii"))
- return to_native_str(out)
+ return uascii_to_str(hash)
#=========================================================
#backend
@@ -316,12 +315,12 @@ class dlitz_pbkdf2_sha1(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
def to_string(self, withchk=True, native=True):
if self.rounds == 400:
- out = u('$p5k2$$%s') % (self.salt,)
+ hash = u('$p5k2$$%s') % (self.salt,)
else:
- out = u('$p5k2$%x$%s') % (self.rounds, self.salt)
+ hash = u('$p5k2$%x$%s') % (self.rounds, self.salt)
if withchk and self.checksum:
- out = u("%s$%s") % (out,self.checksum)
- return to_native_str(out) if native else out
+ hash = u("%s$%s") % (hash,self.checksum)
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
@@ -379,7 +378,7 @@ class atlassian_pbkdf2_sha1(uh.HasStubChecksum, uh.HasRawSalt, uh.HasRawChecksum
def to_string(self):
data = self.salt + (self.checksum or self._stub_checksum)
hash = self.ident + b64encode(data).decode("ascii")
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
#TODO: find out what crowd's policy is re: unicode
@@ -453,7 +452,7 @@ class grub_pbkdf2_sha512(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.Gene
hash = u('%s%d.%s.%s') % (self.ident, self.rounds, salt, chk)
else:
hash = u('%s%d.%s') % (self.ident, self.rounds, salt)
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
#TODO: find out what grub's policy is re: unicode
diff --git a/passlib/handlers/phpass.py b/passlib/handlers/phpass.py
index d83df21..bd72ef8 100644
--- a/passlib/handlers/phpass.py
+++ b/passlib/handlers/phpass.py
@@ -15,8 +15,9 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, handlers as uh, bytes, b, to_unicode, to_native_str
-from passlib.utils.compat import unicode, u
+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
__all__ = [
@@ -110,7 +111,7 @@ class phpass(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.GenericHandler):
h64.encode_int6(self.rounds).decode("ascii"),
self.salt,
self.checksum or u(''))
- return to_native_str(hash)
+ return uascii_to_str(hash)
#=========================================================
#backend
diff --git a/passlib/handlers/postgres.py b/passlib/handlers/postgres.py
index bb4c102..b12db22 100644
--- a/passlib/handlers/postgres.py
+++ b/passlib/handlers/postgres.py
@@ -10,8 +10,9 @@ from warnings import warn
#site
#libs
#pkg
-from passlib.utils import handlers as uh, to_unicode, to_native_str, bytes, b
-from passlib.utils.compat import unicode, u
+from passlib.utils import to_unicode
+from passlib.utils.compat import b, bytes, bascii_to_str, unicode, u
+import passlib.utils.handlers as uh
#local
__all__ = [
"postgres_md5",
@@ -61,8 +62,7 @@ class postgres_md5(uh.StaticHandler):
secret = secret.encode("utf-8")
if isinstance(user, unicode):
user = user.encode("utf-8")
- hash = u("md5") + to_unicode(md5(secret + user).hexdigest())
- return to_native_str(hash)
+ return "md5" + bascii_to_str(md5(secret + user).hexdigest())
#=========================================================
#eoc
diff --git a/passlib/handlers/roundup.py b/passlib/handlers/roundup.py
index 652d913..ac9a189 100644
--- a/passlib/handlers/roundup.py
+++ b/passlib/handlers/roundup.py
@@ -6,7 +6,7 @@
import logging; log = logging.getLogger(__name__)
#site
#libs
-from passlib.utils import handlers as uh
+import passlib.utils.handlers as uh
from passlib.utils.compat import u
#pkg
#local
diff --git a/passlib/handlers/scram.py b/passlib/handlers/scram.py
index 26672c7..80031ed 100644
--- a/passlib/handlers/scram.py
+++ b/passlib/handlers/scram.py
@@ -23,11 +23,12 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import ab64_encode, ab64_decode, xor_bytes, \
- handlers as uh, to_native_str, to_unicode, consteq, saslprep
-from passlib.utils.compat import unicode, bytes, u, b, iteritems, itervalues, \
- PY2, PY3
+from passlib.utils import ab64_decode, ab64_encode, consteq, saslprep, \
+ to_native_str, xor_bytes
+from passlib.utils.compat import b, bytes, bascii_to_str, iteritems, \
+ itervalues, PY3, u, unicode
from passlib.utils.pbkdf2 import pbkdf2, get_prf
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -317,7 +318,7 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
# parse hash
if not hash:
raise ValueError("no hash specified")
- hash = to_native_str(hash, "ascii")
+ hash = to_native_str(hash, "ascii", errname="hash")
if not hash.startswith("$scram$"):
raise ValueError("invalid scram hash")
parts = hash[7:].split("$")
@@ -365,13 +366,11 @@ class scram(uh.HasRounds, uh.HasRawSalt, uh.HasRawChecksum, uh.GenericHandler):
)
def to_string(self, withchk=True):
- salt = ab64_encode(self.salt)
- if PY3:
- salt = salt.decode("ascii")
+ salt = bascii_to_str(ab64_encode(self.salt))
chkmap = self.checksum
if withchk and chkmap:
chk_str = ",".join(
- "%s=%s" % (alg, to_native_str(ab64_encode(chkmap[alg])))
+ "%s=%s" % (alg, bascii_to_str(ab64_encode(chkmap[alg])))
for alg in self.algs
)
else:
diff --git a/passlib/handlers/sha1_crypt.py b/passlib/handlers/sha1_crypt.py
index a23202e..c2eb41d 100644
--- a/passlib/handlers/sha1_crypt.py
+++ b/passlib/handlers/sha1_crypt.py
@@ -13,11 +13,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, handlers as uh, safe_os_crypt, classproperty, \
- to_native_str, to_unicode, bytes, b
-from passlib.utils.compat import unicode
+from passlib.utils import classproperty, h64, safe_os_crypt
+from passlib.utils.compat import b, bytes, u, uascii_to_str, unicode
from passlib.utils.pbkdf2 import hmac_sha1
-from passlib.utils.compat import u
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -92,10 +91,10 @@ class sha1_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandler
)
def to_string(self, native=True):
- out = u("$sha1$%d$%s") % (self.rounds, self.salt)
+ hash = u("$sha1$%d$%s") % (self.rounds, self.salt)
if self.checksum:
- out += u("$") + self.checksum
- return to_native_str(out) if native else out
+ hash += u("$") + self.checksum
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
diff --git a/passlib/handlers/sha2_crypt.py b/passlib/handlers/sha2_crypt.py
index 7b00aad..8da3f1a 100644
--- a/passlib/handlers/sha2_crypt.py
+++ b/passlib/handlers/sha2_crypt.py
@@ -9,9 +9,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, safe_os_crypt, classproperty, handlers as uh, \
- to_native_str, to_unicode, bytes, b, bord
-from passlib.utils.compat import unicode, u, irange
+from passlib.utils import classproperty, h64, safe_os_crypt
+from passlib.utils.compat import b, bytes, belem_ord, irange, u, \
+ uascii_to_str, unicode
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -94,7 +95,7 @@ def raw_sha_crypt(secret, salt, rounds, hash):
dp = extend(tmp.digest(), secret)
#calc DS - hash of salt, extended to size of salt
- tmp = hash(salt * (16+bord(a[0])))
+ tmp = hash(salt * (16+belem_ord(a[0])))
ds = extend(tmp.digest(), salt)
#
@@ -318,7 +319,7 @@ class sha256_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl
hash = u("$5$%s$%s") % (self.salt, self.checksum or u(''))
else:
hash = u("$5$rounds=%d$%s$%s") % (self.rounds, self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
@@ -470,7 +471,7 @@ class sha512_crypt(uh.HasManyBackends, uh.HasRounds, uh.HasSalt, uh.GenericHandl
hash = u("$6$%s$%s") % (self.salt, self.checksum or u(''))
else:
hash = u("$6$rounds=%d$%s$%s") % (self.rounds, self.salt, self.checksum or u(''))
- return to_native_str(hash) if native else hash
+ return uascii_to_str(hash) if native else hash
#=========================================================
#backend
diff --git a/passlib/handlers/sun_md5_crypt.py b/passlib/handlers/sun_md5_crypt.py
index 3bc5f0d..c7b99bb 100644
--- a/passlib/handlers/sun_md5_crypt.py
+++ b/passlib/handlers/sun_md5_crypt.py
@@ -17,8 +17,10 @@ import logging; log = logging.getLogger(__name__)
from warnings import warn
#site
#libs
-from passlib.utils import h64, handlers as uh, to_native_str, to_unicode, bytes, b, bord
-from passlib.utils.compat import trange, unicode, u
+from passlib.utils import h64
+from passlib.utils.compat import b, bytes, belem_ord, trange, u, \
+ uascii_to_str, unicode
+import passlib.utils.handlers as uh
#pkg
#local
__all__ = [
@@ -114,7 +116,7 @@ def raw_sun_md5_crypt(secret, rounds, salt):
round = 0
while round < real_rounds:
#convert last result byte string to list of byte-ints for easy access
- rval = [ bord(c) for c in result ].__getitem__
+ rval = [ belem_ord(c) for c in result ].__getitem__
#build up X bit by bit
x = 0
@@ -309,14 +311,14 @@ class sun_md5_crypt(uh.HasRounds, uh.HasSalt, uh.GenericHandler):
ss = u('') if self.bare_salt else u('$')
rounds = self.rounds
if rounds > 0:
- out = u("$md5,rounds=%d$%s%s") % (rounds, self.salt, ss)
+ hash = u("$md5,rounds=%d$%s%s") % (rounds, self.salt, ss)
else:
- out = u("$md5$%s%s") % (self.salt, ss)
+ hash = u("$md5$%s%s") % (self.salt, ss)
if withchk:
chk = self.checksum
if chk:
- out = u("%s$%s") % (out, chk)
- return to_native_str(out) if native else out
+ hash = u("%s$%s") % (hash, chk)
+ return uascii_to_str(hash) if native else hash
#=========================================================
#primary interface
diff --git a/passlib/tests/test_context.py b/passlib/tests/test_context.py
index bb2f78c..0e5d637 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -18,7 +18,7 @@ except ImportError:
#pkg
from passlib import hash
from passlib.context import CryptContext, CryptPolicy, LazyCryptContext
-from passlib.utils import to_bytes, to_unicode, PasslibPolicyWarning, tick
+from passlib.utils import tick, to_bytes, to_unicode, PasslibPolicyWarning
from passlib.utils.compat import irange, u
import passlib.utils.handlers as uh
from passlib.tests.utils import TestCase, mktemp, catch_warnings, \
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index e04d65f..a4e021d 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -11,8 +11,8 @@ import warnings
#site
#pkg
#module
-from passlib.utils import bytes, b, to_native_str
-from passlib.utils.compat import unicode, PY3, u
+from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY2, PY3, u, \
+ unicode
from passlib.tests.utils import TestCase, Params as ak, enable_option, catch_warnings
def hb(source):
@@ -387,30 +387,32 @@ class CodecTest(TestCase):
"test to_native_str()"
from passlib.utils import to_native_str
- # ascii goes to native string w/o problems
- self.assertEqual(to_native_str(u('abc')), 'abc')
- self.assertEqual(to_native_str(b('abc')), 'abc')
+ # test plain ascii
+ self.assertEqual(to_native_str(u('abc', 'ascii')), 'abc')
+ self.assertEqual(to_native_str(b('abc', 'ascii')), 'abc')
- # other types rejected
- self.assertRaises(TypeError, to_native_str, None)
-
- # non-ascii unicode should throw error under py2, unless codec specified
+ # test invalid ascii
if PY3:
- self.assertEqual(to_native_str(u('\x00\xff')), '\x00\xff')
+ self.assertEqual(to_native_str(u('\xE0'), 'ascii'), '\xE0')
+ self.assertRaises(UnicodeDecodeError, to_native_str, b('\xC3\xA0'),
+ 'ascii')
else:
- self.assertEqual(to_native_str(u('\x00\xff')), '\x00\xc3\xbf')
- self.assertRaises(UnicodeEncodeError, to_native_str, u('\x00\xff'),
+ self.assertRaises(UnicodeEncodeError, to_native_str, u('\xE0'),
'ascii')
+ self.assertEqual(to_native_str(b('\xC3\xA0'), 'ascii'), '\xC3\xA0')
- # non-ascii bytes should throw error under py3, unless codec specified
- if PY3:
- self.assertRaises(UnicodeDecodeError, to_native_str, b('\x00\xff'))
- else:
- self.assertEqual(to_native_str(b('\x00\xff')), '\x00\xff')
+ # test latin-1
+ self.assertEqual(to_native_str(u('\xE0'), 'latin-1'), '\xE0')
+ self.assertEqual(to_native_str(b('\xE0'), 'latin-1'), '\xE0')
+
+ # test utf-8
+ self.assertEqual(to_native_str(u('\xE0'), 'utf-8'),
+ '\xE0' if PY3 else '\xC3\xA0')
+ self.assertEqual(to_native_str(b('\xC3\xA0'), 'utf-8'),
+ '\xE0' if PY3 else '\xC3\xA0')
- # latin-1 should work if explicitly chosen
- self.assertEqual(to_native_str(u('\x00\xff'), 'latin-1'), '\x00\xff')
- self.assertEqual(to_native_str(b('\x00\xff'), 'latin-1'), '\x00\xff')
+ # other types rejected
+ self.assertRaises(TypeError, to_native_str, None, 'ascii')
def test_is_ascii_safe(self):
"test is_ascii_safe()"
@@ -894,7 +896,7 @@ class _MD4_Test(TestCase):
"test md4 digest()"
md4 = self.hash
for input, hex in self.vectors:
- out = to_native_str(hexlify(md4(input).digest()))
+ out = bascii_to_str(hexlify(md4(input).digest()))
self.assertEqual(out, hex)
def test_md4_copy(self):
diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py
index 838d016..9028df4 100644
--- a/passlib/tests/test_utils_handlers.py
+++ b/passlib/tests/test_utils_handlers.py
@@ -13,9 +13,9 @@ import warnings
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
-from passlib.utils import rng, getrandstr, handlers as uh, bytes, b, \
- to_native_str, to_unicode, MissingBackendError, JYTHON
-from passlib.utils.compat import unicode
+from passlib.utils import getrandstr, JYTHON, rng, to_unicode, MissingBackendError
+from passlib.utils.compat import b, bytes, bascii_to_str, uascii_to_str, unicode
+import passlib.utils.handlers as uh
from passlib.tests.utils import HandlerCase, TestCase, catch_warnings, \
dummy_handler_in_registry
from passlib.utils.compat import u
@@ -44,7 +44,7 @@ class SkeletonTest(TestCase):
hash = hash.decode("ascii")
if hash not in (u('a'),u('b')):
raise ValueError
- return to_native_str(u('b') if flag else u('a'))
+ return 'b' if flag else 'a'
#check default identify method
self.assertTrue(d1.identify(u('a')))
@@ -58,7 +58,7 @@ class SkeletonTest(TestCase):
#check default genconfig method
self.assertIs(d1.genconfig(), None)
d1._stub_config = u('b')
- self.assertEqual(d1.genconfig(), to_native_str('b'))
+ self.assertEqual(d1.genconfig(), 'b')
#check default verify method
self.assertTrue(d1.verify('s','a'))
@@ -69,9 +69,9 @@ class SkeletonTest(TestCase):
self.assertRaises(ValueError, d1.verify, 's', 'c')
#check default encrypt method
- self.assertEqual(d1.encrypt('s'), to_native_str('a'))
- self.assertEqual(d1.encrypt('s'), to_native_str('a'))
- self.assertEqual(d1.encrypt('s', flag=True), to_native_str('b'))
+ self.assertEqual(d1.encrypt('s'), 'a')
+ self.assertEqual(d1.encrypt('s'), 'a')
+ self.assertEqual(d1.encrypt('s', flag=True), 'b')
#=========================================================
#GenericHandler & mixins
@@ -411,7 +411,7 @@ class UnsaltedHash(uh.StaticHandler):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
data = b("boblious") + secret
- return to_native_str(hashlib.sha1(data).hexdigest())
+ return bascii_to_str(hashlib.sha1(data).hexdigest())
class SaltedHash(uh.HasSalt, uh.GenericHandler):
"test algorithm with a salt"
@@ -439,13 +439,13 @@ class SaltedHash(uh.HasSalt, uh.GenericHandler):
def to_string(self):
hash = u("@salt%s%s") % (self.salt, self.checksum or self._stub_checksum)
- return to_native_str(hash)
+ return uascii_to_str(hash)
def calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
data = self.salt.encode("ascii") + secret + self.salt.encode("ascii")
- return to_unicode(hashlib.sha1(data).hexdigest(), "latin-1")
+ return hashlib.sha1(data).hexdigest().decode("ascii")
#=========================================================
#test sample algorithms - really a self-test of HandlerCase
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index c9a5aff..85c9ea0 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -10,7 +10,7 @@ import re
import os
import sys
import tempfile
-from passlib.utils.compat import u, PY27, PY_MIN_32, PY3
+from passlib.utils.compat import PY27, PY_MIN_32, PY3
try:
import unittest2 as unittest
@@ -30,12 +30,12 @@ if ut_version < 2:
#used to provide replacement skipTest() method
from nose.plugins.skip import SkipTest
#pkg
-from passlib import registry, utils
-from passlib.utils import classproperty, handlers as uh, \
- has_rounds_info, has_salt_info, MissingBackendError, \
- rounds_cost_values, b, bytes
-from passlib.utils.compat import iteritems, irange, callable, sb_types, \
- exc_err, unicode
+import passlib.registry as registry
+from passlib.utils import has_rounds_info, has_salt_info, MissingBackendError,\
+ rounds_cost_values, classproperty
+from passlib.utils.compat import b, bytes, iteritems, irange, callable, \
+ sb_types, exc_err, u, unicode
+import passlib.utils.handlers as uh
#local
__all__ = [
#util funcs
@@ -542,7 +542,8 @@ class HandlerCase(TestCase):
#this allows use to test as much of the hash's code path
#as possible, even if current OS doesn't provide crypt() support
#for the hash.
- self._orig_os_crypt = utils.os_crypt
+ import passlib.utils as mod
+ self._orig_os_crypt = mod.os_crypt
def crypt_stub(secret, hash):
tmp = h.get_backend()
try:
@@ -553,12 +554,13 @@ class HandlerCase(TestCase):
if not PY3 and isinstance(hash, unicode):
hash = hash.encode("ascii")
return hash
- utils.os_crypt = crypt_stub
+ mod.os_crypt = crypt_stub
h.set_backend(backend)
def tearDown(self):
if self._orig_os_crypt:
- utils.os_crypt = self._orig_os_crypt
+ import passlib.utils as mod
+ mod.os_crypt = self._orig_os_crypt
if self._orig_backend:
self.handler.set_backend(self._orig_backend)
@@ -1006,7 +1008,8 @@ class HandlerCase(TestCase):
possible = True
if handler.has_backend("os_crypt"):
def check_crypt(secret, hash):
- self.assertEqual(utils.os_crypt(secret, hash), hash,
+ from passlib.utils import os_crypt
+ self.assertEqual(os_crypt(secret, hash), hash,
"os_crypt(%r,%r):" % (secret, hash))
helpers.append(check_crypt)
@@ -1076,7 +1079,8 @@ def _enable_backend_case(handler, backend):
if enable_option("all-backends") or _is_default_backend(handler, backend):
if handler.has_backend(backend):
return True, None
- if backend == "os_crypt" and utils.safe_os_crypt:
+ from passlib.utils import has_os_crypt
+ if backend == "os_crypt" and has_os_crypt:
if enable_option("cover") and _has_other_backends(handler, "os_crypt"):
#in this case, HandlerCase will monkeypatch os_crypt
#to use another backend, just so we can test os_crypt fully.
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index 0f53a09..74d53c2 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -17,7 +17,9 @@ import unicodedata
from warnings import warn
#site
#pkg
-from passlib.utils.compat import irange, PY3, unicode, bytes, u, b, _add_doc
+from passlib.utils.compat import _add_doc, b, bytes, bjoin, bjoin_ints, \
+ bjoin_elems, exc_err, irange, imap, PY3, u, \
+ ujoin, unicode
#local
__all__ = [
# constants
@@ -33,9 +35,6 @@ __all__ = [
## "relocated_function",
## "memoized_class_property",
- #byte compat aliases
- 'bytes',
-
# unicode helpers
'consteq',
'saslprep',
@@ -245,7 +244,6 @@ def relocated_function(target, msg=None, name=None, deprecated=None, mod=None,
#=============================================================================
# unicode helpers
#=============================================================================
-ujoin = _UEMPTY.join
def consteq(left, right):
"""check two strings/bytes for equality, taking constant time relative
@@ -431,67 +429,9 @@ def saslprep(source, errname="value"):
return data
-#==========================================================
+#=============================================================================
# bytes helpers
-#==========================================================
-
-#helpers for joining / extracting elements
-bjoin = _BEMPTY.join
-
-#def bjoin_elems(elems):
-# """takes series of bytes elements, returns bytes.
-#
-# elem should be result of bytes[x].
-# this is another bytes instance under py2,
-# but it int under py3.
-#
-# returns bytes.
-#
-# this is bytes() constructor under py3,
-# but b"".join() under py2.
-# """
-# if PY3:
-# return bytes(elems)
-# else:
-# return bjoin(elems)
-#
-#for efficiency, don't bother with above wrapper...
-if PY3:
- bjoin_elems = bytes
-else:
- bjoin_elems = bjoin
-
-#def bord(elem):
-# """takes bytes element, returns integer.
-#
-# elem should be result of bytes[x].
-# this is another bytes instance under py2,
-# but it int under py3.
-#
-# returns int in range(0,256).
-#
-# this is ord() under py2, and noop under py3.
-# """
-# if PY3:
-# assert isinstance(elem, int)
-# return elem
-# else:
-# assert isinstance(elem, bytes)
-# return ord(elem)
-#
-#for efficiency, don't bother with above wrapper...
-if PY3:
- def bord(elem):
- return elem
-else:
- bord = ord
-
-if PY3:
- bjoin_ints = bytes
-else:
- def bjoin_ints(values):
- return bjoin(chr(v) for v in values)
-
+#=============================================================================
if PY3:
def xor_bytes(left, right):
return bytes(l ^ r for l, r in zip(left, right))
@@ -525,9 +465,10 @@ def render_bytes(source, *args):
@deprecated_function(deprecated="1.6", removed="1.8")
def bytes_to_int(value):
"decode string of bytes as single big-endian integer"
+ from passlib.utils.compat import belem_ord
out = 0
for v in value:
- out = (out<<8) | bord(v)
+ out = (out<<8) | belem_ord(v)
return out
@deprecated_function(deprecated="1.6", removed="1.8")
diff --git a/passlib/utils/_blowfish/__init__.py b/passlib/utils/_blowfish/__init__.py
index 41914dd..407b78f 100644
--- a/passlib/utils/_blowfish/__init__.py
+++ b/passlib/utils/_blowfish/__init__.py
@@ -54,9 +54,8 @@ released under the BSD license::
from itertools import chain
import struct
#pkg
-from passlib.utils import Base64Engine, BCRYPT_CHARS, rng, getrandbytes, bytes, bord
-from passlib.utils.compat import b, unicode, u
-from passlib.utils.compat.aliases import BytesIO
+from passlib.utils import Base64Engine, BCRYPT_CHARS, getrandbytes, rng
+from passlib.utils.compat import b, bytes, BytesIO, unicode, u
from passlib.utils._blowfish.unrolled import BlowfishEngine
#local
__all__ = [
diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py
index 5b7750c..26892ea 100644
--- a/passlib/utils/compat.py
+++ b/passlib/utils/compat.py
@@ -12,19 +12,46 @@ PY_MIN_32 = sys.version_info >= (3,2) # py 3.2 or later
#=============================================================================
# common imports
#=============================================================================
+import logging; log = logging.getLogger(__name__)
if PY3:
import builtins
else:
import __builtin__ as builtins
+
+def _add_doc(obj, doc):
+ """add docstring to an object"""
+ obj.__doc__ = doc
+
#=============================================================================
# the default exported vars
#=============================================================================
__all__ = [
- "u", "b",
- "irange", "srange", ##"lrange",
- "lmap",
- "iteritems",
+ # python versions
+ 'PY2', 'PY3', 'PY_MAX_25', 'PY27', 'PY_MIN_32',
+
+ # io
+ 'print_',
+
+ # type detection
+ 'is_mapping',
+ 'callable',
+ 'int_types',
+ 'num_types',
+
+ # unicode/bytes types & helpers
+ 'u', 'b',
+ 'unicode', 'bytes', 'sb_types',
+ 'uascii_to_str', 'bascii_to_str',
+ 'ujoin', 'bjoin', 'bjoin_ints', 'bjoin_elems', 'belem_ord',
+
+ # iteration helpers
+ 'irange', 'trange', #'lrange',
+ 'imap', 'lmap',
+ 'iteritems', 'itervalues',
+
+ # introspection
+ 'exc_err', 'get_method_function', '_add_doc',
]
#=============================================================================
@@ -85,7 +112,6 @@ if (3,0) <= sys.version_info < (3,2):
from collections import Callable
def callable(obj):
return isinstance(obj, Callable)
- __all__.append("callable")
else:
callable = builtins.callable
@@ -97,36 +123,81 @@ else:
num_types = (int, long, float)
#=============================================================================
-# unicode / bytes helpers
+# unicode & bytes types
#=============================================================================
if PY3:
+ unicode = str
+ bytes = builtins.bytes
+# string_types = (unicode,)
+
def u(s):
+ assert isinstance(s, str)
return s
+
def b(s):
assert isinstance(s, str)
return s.encode("latin-1")
- unicode = str
- bytes = builtins.bytes
- __all__.append("unicode")
-# string_types = (unicode,)
else:
def u(s):
+ assert isinstance(s, str)
return s.decode("unicode_escape")
+
def b(s):
assert isinstance(s, str)
return s
- if PY_MAX_25:
- bytes = str
- __all__.append("bytes")
- else:
- bytes = builtins.bytes
- unicode = builtins.unicode
-# string_types = (unicode, bytes)
sb_types = (unicode, bytes)
-# bytes format
+#=============================================================================
+# unicode & bytes helpers
+#=============================================================================
+# function to join list of unicode strings
+ujoin = u('').join
+
+# function to join list of byte strings
+bjoin = b('').join
+
+if PY3:
+ def uascii_to_str(s):
+ assert isinstance(s, unicode)
+ return s
+
+ def bascii_to_str(s):
+ assert isinstance(s, bytes)
+ return s.decode("ascii")
+
+ bjoin_ints = bjoin_elems = bytes
+
+ def belem_ord(elem):
+ return elem
+
+else:
+ def uascii_to_str(s):
+ assert isinstance(s, unicode)
+ return s.encode("ascii")
+
+ def bascii_to_str(s):
+ assert isinstance(s, bytes)
+ return s
+
+ def bjoin_ints(values):
+ return bjoin(chr(v) for v in values)
+
+ bjoin_elems = bjoin
+
+ belem_ord = ord
+
+_add_doc(uascii_to_str, "helper to convert ascii unicode -> native str")
+_add_doc(bascii_to_str, "helper to convert ascii bytes -> native str")
+
+# bjoin_ints -- function to convert list of ordinal integers to byte string.
+
+# bjoin_elems -- function to convert list of byte elements to byte string;
+# i.e. what's returned by ``b('a')[0]``...
+# this is b('a') under PY2, but 97 under PY3.
+
+# belem_ord -- function to convert byte element to integer -- a noop under PY3
#=============================================================================
# iteration helpers
@@ -144,7 +215,7 @@ if PY3:
def lmap(*a, **k):
return list(map(*a,**k))
- # imap = map
+ imap = map
else:
irange = xrange
@@ -152,7 +223,7 @@ else:
##lrange = range
lmap = map
- # from itertools import imap
+ from itertools import imap
if PY3:
def iteritems(d):
@@ -179,10 +250,6 @@ else:
def get_method_function(method):
return method.im_func
-def _add_doc(obj, doc):
- """add docstring to an object"""
- obj.__doc__ = doc
-
#=============================================================================
# input/output
#=============================================================================
diff --git a/passlib/utils/des.py b/passlib/utils/des.py
index ea01048..67c6d93 100644
--- a/passlib/utils/des.py
+++ b/passlib/utils/des.py
@@ -45,8 +45,7 @@ which has some nice notes on how this all works -
# core
import struct
# pkg
-from passlib.utils import bytes, bord, bjoin_ints
-from passlib.utils.compat import trange, irange
+from passlib.utils.compat import bytes, bjoin_ints, belem_ord, irange, trange
# local
__all__ = [
"expand_des_key",
@@ -589,7 +588,7 @@ def expand_des_key(key):
def iter_bits(source):
for c in source:
- v = bord(c)
+ v = belem_ord(c)
for i in irange(7,-1,-1):
yield (v>>i) & 1
diff --git a/passlib/utils/handlers.py b/passlib/utils/handlers.py
index 52ab2cc..7643c01 100644
--- a/passlib/utils/handlers.py
+++ b/passlib/utils/handlers.py
@@ -14,11 +14,11 @@ from warnings import warn
#site
#libs
from passlib.registry import get_crypt_handler
-from passlib.utils import to_native_str, bytes, b, consteq, \
- classproperty, h64, getrandstr, getrandbytes, bjoin_ints, \
- rng, is_crypt_handler, ALL_BYTE_VALUES, MissingBackendError, \
- BASE64_CHARS, HASH64_CHARS
-from passlib.utils.compat import unicode, u, irange
+from passlib.utils import is_crypt_handler
+from passlib.utils import classproperty, consteq, getrandstr, getrandbytes,\
+ BASE64_CHARS, HASH64_CHARS, rng, to_native_str, MissingBackendError
+from passlib.utils.compat import b, bjoin_ints, bytes, irange, u, \
+ uascii_to_str, unicode
#pkg
#local
__all__ = [
@@ -136,7 +136,7 @@ def render_mc2(ident, salt, checksum, sep=u("$")):
hash = u("%s%s%s%s") % (ident, salt, sep, checksum)
else:
hash = u("%s%s") % (ident, salt)
- return to_native_str(hash)
+ return uascii_to_str(hash)
def render_mc3(ident, rounds, salt, checksum, sep=u("$")):
"format hash using 3-part modular crypt format; inverse of parse_mc3"
@@ -144,7 +144,7 @@ def render_mc3(ident, rounds, salt, checksum, sep=u("$")):
hash = u("%s%s%s%s%s%s") % (ident, rounds, sep, salt, sep, checksum)
else:
hash = u("%s%s%s%s") % (ident, rounds, sep, salt)
- return to_native_str(hash)
+ return uascii_to_str(hash)
#=====================================================
#StaticHandler
@@ -1335,7 +1335,7 @@ class PrefixWrapper(object):
if not hash.startswith(orig_prefix):
raise ValueError("not a valid %s hash" % (self.wrapped.name,))
wrapped = self.prefix + hash[len(orig_prefix):]
- return to_native_str(wrapped)
+ return uascii_to_str(wrapped)
def identify(self, hash):
if not hash:
diff --git a/passlib/utils/md4.py b/passlib/utils/md4.py
index df3be70..a63ad11 100644
--- a/passlib/utils/md4.py
+++ b/passlib/utils/md4.py
@@ -15,8 +15,7 @@ from binascii import hexlify
import struct
from warnings import warn
#site
-from passlib.utils import b, bytes, to_native_str
-from passlib.utils.compat import irange, PY3
+from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY3
#local
__all__ = [ "md4" ]
#=========================================================================
@@ -224,8 +223,7 @@ class md4(object):
return out
def hexdigest(self):
- # PY3: hexlify returns bytes, but hexdigest should return str.
- return to_native_str(hexlify(self.digest()))
+ return bascii_to_str(hexlify(self.digest()))
#=========================================================================
#eoc
diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py
index c48f751..c880457 100644
--- a/passlib/utils/pbkdf2.py
+++ b/passlib/utils/pbkdf2.py
@@ -20,9 +20,8 @@ try:
except ImportError:
_EVP = None
#pkg
-from passlib.utils import xor_bytes, to_bytes, b, bytes
-from passlib.utils.compat import irange, callable, int_types
-from passlib.utils.compat.aliases import BytesIO
+from passlib.utils import to_bytes, xor_bytes
+from passlib.utils.compat import b, bytes, BytesIO, irange, callable, int_types
#local
__all__ = [
"hmac_sha1",
diff --git a/passlib/win32.py b/passlib/win32.py
index 19b3ced..a572f9a 100644
--- a/passlib/win32.py
+++ b/passlib/win32.py
@@ -27,8 +27,7 @@ See also :mod:`passlib.hash.nthash`.
from binascii import hexlify
#site
#pkg
-from passlib.utils import b
-from passlib.utils.compat import unicode
+from passlib.utils.compat import b, unicode
from passlib.utils.des import des_encrypt_block
from passlib.hash import nthash
#local