Skip to content

Commit 41903bd

Browse files
committed
update for Python 3.9
1 parent 9842520 commit 41903bd

File tree

4 files changed

+48
-17
lines changed

4 files changed

+48
-17
lines changed

SConstruct

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ env = Environment(
3030
WHEEL_TAG=full_tag,
3131
MSVC_VERSION=MSVC_VERSION,
3232
TARGET_ARCH=TARGET_ARCH,
33+
ENV=os.environ,
3334
)
3435

3536
use_py_limited = "abi3" in full_tag
@@ -49,7 +50,7 @@ extension = env.SharedLibrary(
4950
LIBPREFIX="",
5051
SHLIBSUFFIX=SHLIBSUFFIX,
5152
CPPPATH=[CRYPT_BLOWFISH] + env["CPPPATH"],
52-
CPPFLAGS=["-D__SKIP_GNU"],
53+
CPPFLAGS=["-D__SKIP_GNU", "-DPY_SSIZE_T_CLEAN"],
5354
parse_flags="-DNO_BF_ASM" + " -DPy_LIMITED_API=0x03030000"
5455
if use_py_limited
5556
else "",

cryptacular/crypt/__init__.py

+13-7
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@
3232
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3333
# THE SOFTWARE.
3434

35-
__all__ = ['CRYPTPasswordManager', 'OLDCRYPT', 'MD5CRYPT', 'SHA256CRYPT',
36-
'SHA512CRYPT', 'BCRYPT']
35+
__all__ = [
36+
"CRYPTPasswordManager",
37+
"OLDCRYPT",
38+
"MD5CRYPT",
39+
"SHA256CRYPT",
40+
"SHA512CRYPT",
41+
"BCRYPT",
42+
]
3743

3844
import os
3945
import re
@@ -56,13 +62,14 @@ class CRYPTPasswordManager(object):
5662
def available(self, prefix):
5763
# Lame 'is implemented' check.
5864
try:
59-
l = len(self._crypt('implemented?', prefix + 'xyzzy'))
60-
except TypeError:
65+
l = len(self._crypt("implemented?", prefix + "xyzzy"))
66+
except (TypeError, OSError):
6167
# crypt may return None if prefix is unrecognized
68+
# or raise OSError in Python 3.9+
6269
return False
6370
if prefix == OLDCRYPT:
6471
if l != 13:
65-
return False
72+
return False
6673
elif l < 26:
6774
return False
6875
return True
@@ -76,7 +83,7 @@ def __init__(self, prefix):
7683
def encode(self, password):
7784
"""Hash a password using the builtin crypt module."""
7885
salt = self.PREFIX
79-
salt += base64.b64encode(os.urandom(12), altchars=b'./').decode('utf-8')
86+
salt += base64.b64encode(os.urandom(12), altchars=b"./").decode("utf-8")
8087
password = check_unicode(password)
8188
rc = self._crypt(password, salt)
8289
return rc
@@ -95,4 +102,3 @@ def check(self, encoded, password):
95102
def match(self, hash):
96103
"""Return True if hash starts with our prefix."""
97104
return hash.startswith(self.PREFIX)
98-

cryptacular/crypt/test_crypt.py

+31-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from nose.tools import eq_, raises, assert_false, assert_true, assert_not_equal
33
from cryptacular.crypt import *
44

5+
56
class TestCRYPTPasswordManager(object):
67
snowpass = "hashy the \N{SNOWMAN}"
78

@@ -16,27 +17,37 @@ def test_None1(self):
1617

1718
@raises(TypeError)
1819
def test_None2(self):
19-
self.manager.check(None, 'xyzzy')
20+
self.manager.check(None, "xyzzy")
2021

2122
@raises(TypeError)
2223
def test_None3(self):
23-
hash = self.manager.encode('xyzzy')
24+
hash = self.manager.encode("xyzzy")
2425
self.manager.check(hash, None)
2526

2627
def test_badhash(self):
27-
eq_(self.manager.check('$p5k2$400$ZxK4ZBJCfQg=$kBpklVI9kA13kP32HMZL0rloQ1M=', self.snowpass), False)
28+
try:
29+
eq_(
30+
self.manager.check(
31+
"$p5k2$400$ZxK4ZBJCfQg=$kBpklVI9kA13kP32HMZL0rloQ1M=", self.snowpass
32+
),
33+
False,
34+
)
35+
except OSError:
36+
print("Python 3.9+ crypt() raises OSError on unrecognized hash")
2837

2938
def test_shorthash(self):
3039
manager = self.manager
40+
3141
def match(hash):
3242
return True
43+
3344
manager.match = match
3445
short_hash = manager.encode(self.snowpass)[:11]
3546
assert_true(manager.match(short_hash))
3647
assert_false(manager.check(short_hash, self.snowpass))
3748

3849
def test_emptypass(self):
39-
self.manager.encode('')
50+
self.manager.encode("")
4051

4152
def test_general(self):
4253
manager = self.manager
@@ -50,31 +61,43 @@ def test_general(self):
5061
assert_false(manager.check(password, password))
5162
assert_not_equal(manager.encode(password), manager.encode(password))
5263

53-
available = CRYPTPasswordManager('').available
64+
65+
available = CRYPTPasswordManager("").available
5466

5567
if available(BCRYPT):
68+
5669
class TestCPM_BCRYPT(TestCRYPTPasswordManager):
5770
PREFIX = BCRYPT
5871

72+
5973
if available(MD5CRYPT):
74+
6075
class TestCPM_MD5CRYPT(TestCRYPTPasswordManager):
6176
PREFIX = MD5CRYPT
6277

78+
6379
if available(SHA256CRYPT):
80+
6481
class TestCPM_SHA256CRYPT(TestCRYPTPasswordManager):
6582
PREFIX = SHA256CRYPT
6683

84+
6785
if available(SHA512CRYPT):
86+
6887
class TestCPM_SHA512CRYPT(TestCRYPTPasswordManager):
6988
PREFIX = SHA512CRYPT
7089

90+
7191
@raises(NotImplementedError)
7292
def test_bogocrypt():
73-
CRYPTPasswordManager('$bogo$')
93+
CRYPTPasswordManager("$bogo$")
94+
7495

7596
@raises(NotImplementedError)
7697
def test_oddcrypt():
7798
"""crypt.crypt with empty prefix returns hash != 13 characters?"""
99+
78100
class BCPM(CRYPTPasswordManager):
79-
_crypt = lambda x, y, z: '4' * 14
80-
BCPM('')
101+
_crypt = lambda x, y, z: "4" * 14
102+
103+
BCPM("")

pyproject.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "enscons.api"
44

55
[tool.enscons]
66
name = "cryptacular"
7-
version = "1.6.1"
7+
version = "1.6.2"
88
description = "A password hashing framework with bcrypt and pbkdf2."
99
classifiers = ["Development Status :: 5 - Production/Stable",
1010
"Intended Audience :: Developers",
@@ -13,6 +13,7 @@ classifiers = ["Development Status :: 5 - Production/Stable",
1313
"Programming Language :: Python :: 2.7",
1414
"Programming Language :: Python :: 3",
1515
"Programming Language :: Python :: 3.6",
16+
"Programming Language :: Python :: 3.9",
1617
"Programming Language :: Python :: Implementation :: CPython",
1718
"Programming Language :: Python :: Implementation :: PyPy",
1819
"Programming Language :: C",

0 commit comments

Comments
 (0)