diff --git a/CHANGELOG.md b/CHANGELOG.md index afe6fc09..1fb56d6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This document describes changes between each past release. ## 6.1.1 (unreleased) -- Nothing changed yet. +- Speed up unit tests (#1214) ## 6.1.0 (2023-07-29) diff --git a/docs/configuration.md b/docs/configuration.md index 70f3a4e1..842f0551 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -188,3 +188,12 @@ project](https://pythonhosted.org/flask-mail/#configuring-flask-mail) - **MAIL_USERNAME** : default **None** - **MAIL_PASSWORD** : default **None** - **DEFAULT_MAIL_SENDER** : default **None** + +## Configuring password hashes + +The werkzeug [generate_password_hash](https://werkzeug.palletsprojects.com/utils/#werkzeug.security.generate_password_hash) +is used to create password hashes. By default the default werkzeug values +are used, however you can customize those values with: + +- **PASSWORD_HASH_METHOD** : default **None** +- **PASSWORD_HASH_SALT_LENGTH** : default **None** diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 17711989..72f9d122 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -9,7 +9,7 @@ from flask_babel import lazy_gettext as _ from flask_wtf.file import FileAllowed, FileField, FileRequired from flask_wtf.form import FlaskForm from markupsafe import Markup -from werkzeug.security import check_password_hash, generate_password_hash +from werkzeug.security import check_password_hash from wtforms.fields import ( BooleanField, DateField, @@ -43,6 +43,7 @@ from ihatemoney.models import Bill, LoggingMode, Person, Project from ihatemoney.utils import ( em_surround, eval_arithmetic_expression, + generate_password_hash, render_localized_currency, slugify, ) diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index ad822f4d..6ba2277f 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -7,11 +7,10 @@ import sys import click from flask.cli import FlaskGroup -from werkzeug.security import generate_password_hash from ihatemoney.models import Project, db from ihatemoney.run import create_app -from ihatemoney.utils import create_jinja_env +from ihatemoney.utils import create_jinja_env, generate_password_hash @click.group(cls=FlaskGroup, create_app=create_app) diff --git a/ihatemoney/models.py b/ihatemoney/models.py index 74170fef..c1aeaa2a 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -18,11 +18,10 @@ from sqlalchemy import orm from sqlalchemy.sql import func from sqlalchemy_continuum import make_versioned, version_class from sqlalchemy_continuum.plugins import FlaskPlugin -from werkzeug.security import generate_password_hash from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.monkeypath_continuum import PatchedTransactionFactory -from ihatemoney.utils import get_members, same_bill +from ihatemoney.utils import generate_password_hash, get_members, same_bill from ihatemoney.versioning import ( ConditionalVersioningManager, LoggingMode, diff --git a/ihatemoney/tests/budget_test.py b/ihatemoney/tests/budget_test.py index 89efeb2d..fff641ad 100644 --- a/ihatemoney/tests/budget_test.py +++ b/ihatemoney/tests/budget_test.py @@ -7,12 +7,13 @@ from urllib.parse import urlparse, urlunparse from flask import session, url_for from libfaketime import fake_time import pytest -from werkzeug.security import check_password_hash, generate_password_hash +from werkzeug.security import check_password_hash from ihatemoney import models from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.tests.common.help_functions import extract_link from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase +from ihatemoney.utils import generate_password_hash from ihatemoney.versioning import LoggingMode from ihatemoney.web import build_etag diff --git a/ihatemoney/tests/common/ihatemoney_testcase.py b/ihatemoney/tests/common/ihatemoney_testcase.py index 73d14ec2..94b5161a 100644 --- a/ihatemoney/tests/common/ihatemoney_testcase.py +++ b/ihatemoney/tests/common/ihatemoney_testcase.py @@ -2,11 +2,11 @@ import os from unittest.mock import MagicMock from flask_testing import TestCase -from werkzeug.security import generate_password_hash from ihatemoney import models from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.run import create_app, db +from ihatemoney.utils import generate_password_hash class BaseTestCase(TestCase): @@ -15,6 +15,8 @@ class BaseTestCase(TestCase): "TESTING_SQLALCHEMY_DATABASE_URI", "sqlite://" ) ENABLE_CAPTCHA = False + PASSWORD_HASH_METHOD = "pbkdf2:sha1:1" + PASSWORD_HASH_SALT_LENGTH = 1 def create_app(self): # Pass the test object as a configuration. diff --git a/ihatemoney/tests/ihatemoney.cfg b/ihatemoney/tests/ihatemoney.cfg index 31247584..16c7534e 100644 --- a/ihatemoney/tests/ihatemoney.cfg +++ b/ihatemoney/tests/ihatemoney.cfg @@ -7,3 +7,6 @@ SQLACHEMY_ECHO = DEBUG SECRET_KEY = "supersecret" MAIL_DEFAULT_SENDER = "Budget manager " + +PASSWORD_HASH_METHOD = "pbkdf2:sha1:1" +PASSWORD_HASH_SALT_LENGTH = 1 diff --git a/ihatemoney/tests/ihatemoney_envvar.cfg b/ihatemoney/tests/ihatemoney_envvar.cfg index 05306127..6832951a 100644 --- a/ihatemoney/tests/ihatemoney_envvar.cfg +++ b/ihatemoney/tests/ihatemoney_envvar.cfg @@ -7,3 +7,6 @@ SQLACHEMY_ECHO = DEBUG SECRET_KEY = "lalatra" MAIL_DEFAULT_SENDER = "Budget manager " + +PASSWORD_HASH_METHOD = "pbkdf2:sha1:1" +PASSWORD_HASH_SALT_LENGTH = 1 diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index 554d0eec..281cdf51 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -20,6 +20,7 @@ import jinja2 from markupsafe import Markup, escape from werkzeug.exceptions import HTTPException from werkzeug.routing import RoutingException +from werkzeug.security import generate_password_hash as werkzeug_generate_password_hash limiter = limiter = Limiter( current_app, @@ -448,3 +449,15 @@ def format_form_errors(form, prefix): errors = f"" # I18N: Form error with a list of errors return Markup(_("{prefix}:
{errors}").format(prefix=prefix, errors=errors)) + + +def generate_password_hash(*args, **kwargs): + if current_app.config.get("PASSWORD_HASH_METHOD"): + kwargs.setdefault("method", current_app.config["PASSWORD_HASH_METHOD"]) + + if current_app.config.get("PASSWORD_HASH_SALT_LENGTH"): + kwargs.setdefault( + "salt_length", current_app.config["PASSWORD_HASH_SALT_LENGTH"] + ) + + return werkzeug_generate_password_hash(*args, **kwargs) diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 8ea18779..d9aa2bbd 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -36,7 +36,7 @@ import qrcode import qrcode.image.svg from sqlalchemy_continuum import Operation from werkzeug.exceptions import NotFound -from werkzeug.security import check_password_hash, generate_password_hash +from werkzeug.security import check_password_hash from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.emails import send_creation_email @@ -63,6 +63,7 @@ from ihatemoney.utils import ( csv2list_of_dicts, flash_email_error, format_form_errors, + generate_password_hash, limiter, list_of_dicts2csv, list_of_dicts2json,