diff --git a/app.py b/app.py index 1a65aad8ec1..cea51e25099 100644 --- a/app.py +++ b/app.py @@ -2934,7 +2934,7 @@ def on_offline_mode(): # own file loading routines also hot-reload. no_debug_mode_requested = os.getenv('NO_DEBUG_MODE') utils.set_debug_mode(not no_debug_mode_requested) - + utils.limiter.init_app(app) if utils.is_offline_mode(): on_offline_mode() diff --git a/requirements.txt b/requirements.txt index 74425cc7276..477fd0d2a58 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,3 +36,4 @@ uflash>=2.0.0 pyinstaller==6.3.0 commonmark==0.9.1 check-jsonschema +flask-limiter==3.5.0 diff --git a/utils.py b/utils.py index c80e844cd0f..f3211bafdb8 100644 --- a/utils.py +++ b/utils.py @@ -22,6 +22,15 @@ from ruamel import yaml import commonmark +from flask_limiter import Limiter +from flask_limiter.util import get_remote_address + +# Implement the rate limiter +limiter = Limiter( + get_remote_address, + storage_uri="memory://", +) + commonmark_parser = commonmark.Parser() commonmark_renderer = commonmark.HtmlRenderer() diff --git a/website/auth_pages.py b/website/auth_pages.py index 12c9e621db9..4c4480142e8 100644 --- a/website/auth_pages.py +++ b/website/auth_pages.py @@ -2,7 +2,6 @@ from flask import make_response, redirect, request, session from flask_babel import gettext - from config import config from safe_format import safe_format from hedy_content import ALL_LANGUAGES, COUNTRIES @@ -29,7 +28,7 @@ send_email_template, validate_signup_data, ) - +from utils import limiter from .database import Database from .website_module import WebsiteModule, route @@ -371,6 +370,7 @@ def recover(self): return make_response({"message": gettext("sent_password_recovery")}, 200) @route("/reset", methods=["POST"]) + @limiter.limit("1/day;1/hour;1/minute", exempt_when=lambda: is_testing_request(request)) def reset(self): body = request.json # Validations