diff --git a/coremods/control.py b/coremods/control.py index 0805f47..a918599 100644 --- a/coremods/control.py +++ b/coremods/control.py @@ -9,7 +9,7 @@ import atexit from pylinkirc import world, utils, conf # Do not import classes, it'll import loop from pylinkirc.log import log, _make_file_logger, _stop_file_loggers, _get_console_log_level -from . import permissions +from . import permissions, login def remove_network(ircobj): """Removes a network object from the pool.""" @@ -104,6 +104,7 @@ def rehash(): log.debug('rehash: updating console log level') world.console_handler.setLevel(_get_console_log_level()) + login._make_cryptcontext() # refresh password hashing settings for network, ircobj in world.networkobjects.copy().items(): # Server was removed from the config file, disconnect them. diff --git a/coremods/login.py b/coremods/login.py index 5cd03b3..7559776 100644 --- a/coremods/login.py +++ b/coremods/login.py @@ -5,18 +5,30 @@ login.py - Implement core login abstraction. from pylinkirc import conf, utils, world from pylinkirc.log import log -try: - from passlib.context import CryptContext -except ImportError: - CryptContext = None - log.warning("Hashed passwords are disabled because passlib is not installed. Please install " - "it (pip3 install passlib) and restart for this feature to work.") - +# PyLink's global password context pwd_context = None -if CryptContext: - pwd_context = CryptContext(["sha512_crypt", "sha256_crypt"], - sha256_crypt__default_rounds=180000, - sha512_crypt__default_rounds=90000) + +_DEFAULT_CRYPTCONTEXT_SETTINGS = { + 'schemes': ["pbkdf2_sha256", "sha512_crypt"] +} +def _make_cryptcontext(): + try: + from passlib.context import CryptContext + except ImportError: + log.warning("Hashed passwords are disabled because passlib is not installed. Please install " + "it (pip3 install passlib) and rehash for this feature to work.") + return + + context_settings = conf.conf.get('login', {}).get('cryptcontext_settings') or _DEFAULT_CRYPTCONTEXT_SETTINGS + global pwd_context + if pwd_context is None: + log.debug("Initialized new CryptContext with settings: %s", context_settings) + pwd_context = CryptContext(**context_settings) + else: + log.debug("Updated CryptContext with settings: %s", context_settings) + pwd_context.update(**context_settings) + +_make_cryptcontext() # This runs at startup and in rehash (control.py) def _get_account(accountname): """ diff --git a/example-conf.yml b/example-conf.yml index 5ac6eeb..3d0d430 100644 --- a/example-conf.yml +++ b/example-conf.yml @@ -117,6 +117,16 @@ login: # are supported here as well. #hosts: ["*!*@localhost", "*!*@trusted.isp"] + # For ADVANCED users: adjusts settings for PyLink's default passlib CryptContext. + # As of PyLink 2.1, the default is to use pbkdf2_sha256 for new hashes, while also allowing verifying + # sha512_crypt for compatibility with PyLink < 2.1. + + # This is configured as a dict of settings, which will be passed into the CryptContext constructor. + # See https://passlib.readthedocs.io/en/stable/lib/passlib.context.html for a list of valid options. + # Changes to this setting require a rehash to apply. + #cryptcontext_settings: + #schemes: ["pbkdf2_sha256", "sha512_crypt"] + permissions: # Permissions blocks in PyLink are define as a mapping of PyLink targets (i.e. hostmasks or # exttargets) to lists of permission nodes. You can find a list of permissions that PyLink and