diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 5276063d..6f1a570b 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -1052,7 +1052,6 @@ Available methods: * `bcrypt` This uses a modified version of the Blowfish stream cipher, which is considered very secure. The installation of Python's **bcrypt** module is required for this to work. - Also consider version of passlib(libpass): bcrypt >= 5.0.0 requires passlib(libpass) >= 1.9.3 * `md5` Use an iterated MD5 digest of the password with salt (nowadays insecure). diff --git a/pyproject.toml b/pyproject.toml index 45d68916..8ef5c452 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ classifiers = [ ] urls = {Homepage = "https://radicale.org/"} requires-python = ">=3.9.0" -# Hint: if bcyrpt < 5.0.0 is used, passlib(libpass) dependency can be downgraded/reverted by: sed -i 's|libpass[^"]*|passlib|' pyproject.toml +# Hint: passlib(libpass) dependency can be downgraded/reverted by: sed -i 's|libpass[^"]*|passlib|' pyproject.toml dependencies = [ "defusedxml", "libpass>=1.9.3", diff --git a/radicale/auth/htpasswd.py b/radicale/auth/htpasswd.py index 0c25be11..a179f3cb 100644 --- a/radicale/auth/htpasswd.py +++ b/radicale/auth/htpasswd.py @@ -43,7 +43,7 @@ out-of-the-box: - SHA256 (htpasswd -2 ...) - SHA512 (htpasswd -5 ...) -When bcrypt is installed (bcrypt >= 5.0.0 requires passlib(libpass) >= 1.9.3): +When bcrypt is installed: - BCRYPT (htpasswd -B ...) -- Requires htpasswd 2.4.x When argon2 is installed: @@ -61,7 +61,7 @@ from typing import Any, Tuple from passlib.hash import apr_md5_crypt, sha256_crypt, sha512_crypt -from radicale import auth, config, logger, utils +from radicale import auth, config, logger class Auth(auth.BaseAuth): @@ -122,22 +122,12 @@ class Auth(auth.BaseAuth): "The htpasswd encryption method 'bcrypt' or 'autodetect' requires " "the bcrypt module (entries found: %d)." % self._htpasswd_bcrypt_use) from e else: - [bcrypt_usable, info] = utils.passlib_libpass_supports_bcrypt() - if bcrypt_usable: - self._has_bcrypt = True - logger.info(info) - else: - logger.warning(info) + self._has_bcrypt = True if self._encryption == "autodetect": if self._htpasswd_bcrypt_use == 0: logger.info("auth htpasswd encryption is 'radicale.auth.htpasswd_encryption.%s' and bcrypt module found, but currently not required", self._encryption) else: logger.info("auth htpasswd encryption is 'radicale.auth.htpasswd_encryption.%s' and bcrypt module found (bcrypt entries found: %d)", self._encryption, self._htpasswd_bcrypt_use) - if not bcrypt_usable: - raise RuntimeError("The htpasswd encryption 'autodetect' requires the bcrypt module but not usuable") - else: - if not bcrypt_usable: - raise RuntimeError("The htpasswd encryption method 'bcrypt' requires the bcrypt module but not usuable") if self._encryption == "bcrypt": self._verify = functools.partial(self._bcrypt, bcrypt) else: diff --git a/radicale/tests/test_auth.py b/radicale/tests/test_auth.py index e7c8409d..8051e0f5 100644 --- a/radicale/tests/test_auth.py +++ b/radicale/tests/test_auth.py @@ -31,7 +31,7 @@ from typing import Iterable, Tuple, Union import pytest -from radicale import utils, xmlutils +from radicale import xmlutils from radicale.auth import htpasswd from radicale.tests import BaseTest @@ -133,52 +133,42 @@ class TestBaseAuthRequests(BaseTest): self._test_htpasswd("autodetect", "tmp:$6$rounds=2500$A1H/cZUl3CBnsplz$bSKYCDQ/YGR..YhxaZcM1eKmAi/jlnpbENKU8a.9kE95JBIpyUss3.cUyss0xQnhjD4PReN4sAzmdziWmoCsg/") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_2a(self) -> None: self._test_htpasswd("bcrypt", "tmp:$2a$10$Mj4A9vMecAp/K7.0fMKoVOk1SjgR.RBhl06a52nvzXhxlT3HB7Reu") - @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed or incompatibe") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") + @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") def test_htpasswd_bcrypt_2a_autodetect(self) -> None: self._test_htpasswd("autodetect", "tmp:$2a$10$Mj4A9vMecAp/K7.0fMKoVOk1SjgR.RBhl06a52nvzXhxlT3HB7Reu") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_2b(self) -> None: self._test_htpasswd("bcrypt", "tmp:$2b$12$7a4z/fdmXlBIfkz0smvzW.1Nds8wpgC/bo2DVOb4OSQKWCDL1A1wu") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_2b_autodetect(self) -> None: self._test_htpasswd("autodetect", "tmp:$2b$12$7a4z/fdmXlBIfkz0smvzW.1Nds8wpgC/bo2DVOb4OSQKWCDL1A1wu") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_2y(self) -> None: self._test_htpasswd("bcrypt", "tmp:$2y$05$oD7hbiQFQlvCM7zoalo/T.MssV3VNTRI3w5KDnj8NTUKJNWfVpvRq") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_2y_autodetect(self) -> None: self._test_htpasswd("autodetect", "tmp:$2y$05$oD7hbiQFQlvCM7zoalo/T.MssV3VNTRI3w5KDnj8NTUKJNWfVpvRq") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_C10(self) -> None: self._test_htpasswd("bcrypt", "tmp:$2y$10$bZsWq06ECzxqi7RmulQvC.T1YHUnLW2E3jn.MU2pvVTGn1dfORt2a") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_C10_autodetect(self) -> None: self._test_htpasswd("autodetect", "tmp:$2y$10$bZsWq06ECzxqi7RmulQvC.T1YHUnLW2E3jn.MU2pvVTGn1dfORt2a") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_unicode(self) -> None: self._test_htpasswd("bcrypt", "😀:$2y$10$Oyz5aHV4MD9eQJbk6GPemOs4T6edK6U9Sqlzr.W1mMVCS8wJUftnW", "unicode") @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_htpasswd_bcrypt_long(self) -> None: import bcrypt m = ( @@ -193,7 +183,6 @@ class TestBaseAuthRequests(BaseTest): self._test_htpasswd("bcrypt", "tmp:" + hash.decode('utf-8'), m) @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") - @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") def test_bcrypt_hash_long(self) -> None: import bcrypt salt = bcrypt.gensalt() diff --git a/radicale/utils.py b/radicale/utils.py index ca4da132..fd56f286 100644 --- a/radicale/utils.py +++ b/radicale/utils.py @@ -27,8 +27,6 @@ from importlib import import_module, metadata from string import ascii_letters, digits, punctuation from typing import Callable, Sequence, Tuple, Type, TypeVar, Union -from packaging.version import Version - from radicale import config from radicale.log import logger @@ -109,30 +107,6 @@ def vobject_supports_vcard4() -> bool: return False -def passlib_libpass_supports_bcrypt() -> Tuple[bool, str]: - """Check if passlib(libpass) version supports bcrypt version.""" - info = "" - try: - version_bcrypt = package_version("bcrypt") - version_bcrypt_check = "5.0.0" - version_passlib = package_version("passlib") - version_passlib_check = "1.9.3" - if Version(version_bcrypt) >= Version(version_bcrypt_check): - # bcrypt >= 5.0.0 has issues with passlib(libpass) < 1.9.3 - if Version(version_passlib) < Version(version_passlib_check): - info = "bcrypt module version %r >= %r and passlib(libpass) module version %r < %r found => incompatible, downgrade bcrypt or upgrade passlib(libpass)" % (version_bcrypt, version_bcrypt_check, version_passlib, version_passlib_check) - return (False, info) - else: - info = "bcrypt module version %r >= %r and passlib(libpass) module version %r >= %r found => ok" % (version_bcrypt, version_bcrypt_check, version_passlib, version_passlib_check) - return (True, info) - else: - info = "bcrypt module version %r < %r and passlib(libpass) module version %r found => ok" % (version_bcrypt, version_bcrypt_check, version_passlib) - return (True, info) - except Exception: - info = "bcrypt module version or passlib(libpass) module version %r not found => problem" - return (False, info) - - def packages_version(): versions = [] versions.append("python=%s.%s.%s" % (sys.version_info[0], sys.version_info[1], sys.version_info[2])) diff --git a/setup.py.legacy b/setup.py.legacy index bba4e406..bae2e432 100644 --- a/setup.py.legacy +++ b/setup.py.legacy @@ -37,7 +37,7 @@ web_files = ["web/internal_data/css/icon.png", "web/internal_data/js/utils/*.js", "web/internal_data/index.html"] -# Hint: if bcyrpt < 5.0.0 is used, passlib(libpass) dependency can be downgraded/reverted by: sed -i 's|libpass[^"]*|passlib|' setup.py.legacy +# Hint: passlib(libpass) dependency can be downgraded/reverted by: sed -i 's|libpass[^"]*|passlib|' setup.py.legacy install_requires = ["defusedxml", "libpass>=1.9.3", "vobject>=0.9.6", "pika>=1.1.0", "requests",