From 101dbdc96b029bdfb86e9aa3f4ea6d2c20858fd9 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Sun, 19 Oct 2025 12:58:34 -0500 Subject: [PATCH] feat: use bcrypt directly instead of passlib apparently passlib has not been updated in years, and the combo with latest bcrypt v5 was causing errors https://github.com/pyca/bcrypt/issues/1082 https://github.com/pyca/bcrypt/issues/1079 https://foss.heptapod.net/python-libs/passlib/-/issues/196 --- pyproject.toml | 3 ++- src/wuttjamaican/auth.py | 17 ++++++----------- tests/test_app.py | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c4edb2d..18bc4d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ ] requires-python = ">= 3.8" dependencies = [ + "bcrypt", "humanize", 'importlib-metadata; python_version < "3.10"', "importlib_resources ; python_version < '3.9'", @@ -39,7 +40,7 @@ dependencies = [ [project.optional-dependencies] -db = ["SQLAlchemy", "alembic", "alembic-postgresql-enum", "passlib"] +db = ["SQLAlchemy", "alembic", "alembic-postgresql-enum"] docs = ["Sphinx", "sphinxcontrib-programoutput", "enum-tools[sphinx]", "furo"] tests = ["pylint", "pytest", "pytest-cov", "tox"] diff --git a/src/wuttjamaican/auth.py b/src/wuttjamaican/auth.py index ac6dbe6..bd63f23 100644 --- a/src/wuttjamaican/auth.py +++ b/src/wuttjamaican/auth.py @@ -29,18 +29,11 @@ This defines the default :term:`auth handler`. import secrets import uuid as _uuid +import bcrypt + from wuttjamaican.app import GenericHandler -# nb. this only works if passlib is installed (part of 'db' extra) -try: - from passlib.context import CryptContext -except ImportError: # pragma: no cover - pass -else: - password_context = CryptContext(schemes=["bcrypt"]) - - class AuthHandler(GenericHandler): # pylint: disable=too-many-public-methods """ Base class and default implementation for the :term:`auth @@ -143,7 +136,7 @@ class AuthHandler(GenericHandler): # pylint: disable=too-many-public-methods :returns: ``True`` if password matches; else ``False``. """ - return password_context.verify(password, user.password) + return bcrypt.checkpw(password.encode("utf-8"), user.password.encode("utf-8")) def get_role(self, session, key): """ @@ -419,7 +412,9 @@ class AuthHandler(GenericHandler): # pylint: disable=too-many-public-methods :param password: New password in plain text. """ - user.password = password_context.hash(password) + user.password = bcrypt.hashpw( + password.encode("utf-8"), bcrypt.gensalt() + ).decode("utf-8") def get_role_administrator(self, session): """ diff --git a/tests/test_app.py b/tests/test_app.py index 1b0e19c..2a0c89e 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -415,8 +415,8 @@ app_title = WuttaTest self.assertEqual(ver, version("SQLAlchemy")) # can also specify the dist - ver = self.app.get_version(dist="passlib") - self.assertEqual(ver, version("passlib")) + ver = self.app.get_version(dist="progress") + self.assertEqual(ver, version("progress")) def test_make_title(self): text = self.app.make_title("foo_bar")