Add optional support for a simple CAPTCHA.

This commit is contained in:
Alexis Métaireau 2021-10-06 00:25:42 +02:00 committed by Glandos
parent e626a1cbea
commit 0fff98eea0
9 changed files with 40 additions and 4 deletions

View file

@ -155,6 +155,11 @@ Note: this setting is actually interpreted by Flask-Babel, see the
.. _Flask-Babel guide for formatting dates: https://pythonhosted.org/Flask-Babel/#formatting-dates
`ENABLE_CAPTCHA`
---------------
It is possible to add a simple captcha in order to filter out spammer bots on the form creation.
In order to do so, you just have to set `ENABLE_CAPTCHA = True`.
Configuring emails sending
--------------------------

View file

@ -42,3 +42,7 @@ ACTIVATE_ADMIN_DASHBOARD = False
# Enable secure cookies. Requires HTTPS. Disable if you run your ihatemoney
# service over plain HTTP.
SESSION_COOKIE_SECURE = True
# You can activate an optional CAPTCHA if you want to. It can be helpful
# to filter spammer bots.
# ENABLE_CAPTCHA = True

View file

@ -32,3 +32,4 @@ SUPPORTED_LANGUAGES = [
"uk",
"zh_Hans",
]
ENABLE_CAPTCHA = False

View file

@ -3,12 +3,13 @@ from re import match
from types import SimpleNamespace
import email_validator
from flask import request
from flask import current_app, request
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 wtforms.fields import Field
from wtforms.fields.core import Label, SelectField, SelectMultipleField
from wtforms.fields.html5 import DateField, DecimalField, URLField
from wtforms.fields.simple import BooleanField, PasswordField, StringField, SubmitField
@ -221,6 +222,16 @@ class ProjectForm(EditProjectForm):
)
raise ValidationError(Markup(message))
@classmethod
def enable_captcha(cls):
captchaField = StringField(_("Which is a real currency: Euro or Petro dollar?"))
setattr(cls, "captcha", captchaField)
def validate_captcha(form, field):
if not field.data.lower() == _("euro"):
message = _("Please, validate the captcha to proceed.")
raise ValidationError(Markup(message))
class DestructiveActionProjectForm(FlaskForm):
"""Used for any important "delete" action linked to a project:

View file

@ -75,6 +75,9 @@
{{ input(form.name) }}
{{ input(form.password) }}
{{ input(form.contact_email) }}
{% if config['ENABLE_CAPTCHA'] %}
{{ input(form.captcha) }}
{% endif %}
{{ input(form.default_currency) }}
{% if not home %}
{{ submit(form.submit, home=True) }}
@ -171,7 +174,7 @@
</div>
</div>
</div>
<details class="mb-3">
<summary class="mb-2">{{ _("More options") }}</summary>
{% if g.project.default_currency != "XXX" %}

View file

@ -17,6 +17,8 @@ from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase
from ihatemoney.versioning import LoggingMode
class BudgetTestCase(IhatemoneyTestCase):
def test_notifications(self):
"""Test that the notifications are sent, and that email addresses
@ -310,6 +312,7 @@ class BudgetTestCase(IhatemoneyTestCase):
# project removed
self.assertEqual(len(models.Project.query.all()), 0)
def test_bill_placeholder(self):
self.post_project("raclette")
self.login("raclette")

View file

@ -15,6 +15,7 @@ class BaseTestCase(TestCase):
SQLALCHEMY_DATABASE_URI = os.environ.get(
"TESTING_SQLALCHEMY_DATABASE_URI", "sqlite://"
)
ENABLE_CAPTCHA = False
def create_app(self):
# Pass the test object as a configuration.

View file

@ -31,6 +31,7 @@ class ConfigurationTestCase(BaseTestCase):
self.assertTrue(self.app.config["ACTIVATE_DEMO_PROJECT"])
self.assertTrue(self.app.config["ALLOW_PUBLIC_PROJECT_CREATION"])
self.assertFalse(self.app.config["ACTIVATE_ADMIN_DASHBOARD"])
self.assertFalse(self.app.config["ENABLE_CAPTCHA"])
def test_env_var_configuration_file(self):
"""Test that settings are loaded from a configuration file specified

View file

@ -260,9 +260,16 @@ def authenticate(project_id=None):
return render_template("authenticate.html", form=form)
def get_project_form():
if current_app.config.get("ENABLE_CAPTCHA", False):
ProjectForm.enable_captcha()
return ProjectForm()
@main.route("/", strict_slashes=False)
def home():
project_form = ProjectForm()
project_form = get_project_form()
auth_form = AuthenticationForm()
is_demo_project_activated = current_app.config["ACTIVATE_DEMO_PROJECT"]
is_public_project_creation_allowed = current_app.config[
@ -287,7 +294,7 @@ def mobile():
@main.route("/create", methods=["GET", "POST"])
@requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True))
def create_project():
form = ProjectForm()
form = get_project_form()
if request.method == "GET" and "project_id" in request.values:
form.name.data = request.values["project_id"]