1# Copyright (C) 2012-2020 by the Free Software Foundation, Inc. 2# 3# This file is part of GNU Mailman. 4# 5# GNU Mailman is free software: you can redistribute it and/or modify it under 6# the terms of the GNU General Public License as published by the Free 7# Software Foundation, either version 3 of the License, or (at your option) 8# any later version. 9# 10# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT 11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13# more details. 14# 15# You should have received a copy of the GNU General Public License along with 16# GNU Mailman. If not, see <https://www.gnu.org/licenses/>. 17 18"""A wrapper around passlib.""" 19 20from mailman.config.config import load_external 21from mailman.interfaces.configuration import ConfigurationUpdatedEvent 22from passlib.context import CryptContext 23from public import public 24 25 26class PasswordContext: 27 def __init__(self, config): 28 """Create a password context for hashing and verification. 29 30 :param config: The `IConfiguration` instance. 31 """ 32 config_string = load_external(config.passwords.configuration) 33 self._context = CryptContext.from_string(config_string) 34 35 def encrypt(self, secret): 36 """Return the secret, hashed using the current password context. 37 38 :param secret: The plain text password. 39 :type secret: string 40 :return: The hashed secret. 41 :rtype: string 42 """ 43 return self._context.encrypt(secret) 44 45 def verify(self, password, hashed): 46 """Verify the hashed password and return the updated hash. 47 48 This is essentially a wrapper around 49 `passlib.CryptContext.verify_and_update()` using only the first two 50 arguments. 51 52 :param password: The plain text secret provided by the user. 53 :type password: 54 :param hashed: The hash string to compare to. 55 :type hashed: string 56 :return: 2-tuple where the first element is a flag indicating whether 57 the password verified or not, and the second value whether the 58 existing hash needs to be replaced (a str if so, else None). 59 :rtype: 2-tuple 60 """ 61 return self._context.verify_and_update(password, hashed) 62 63 64@public 65def handle_ConfigurationUpdatedEvent(event): 66 if isinstance(event, ConfigurationUpdatedEvent): 67 # Just reset the password context. 68 event.config.password_context = PasswordContext(event.config) 69