Do not require a captcha when using the API

This was trickier than expected, due to some side effects : when the
captcha is set to `True` via configuration, it doesn't change the
behavior directly of the ProjectForm class, but does so only when the
project form is used in the `web.py` module.

So, when just using the API (and not using the web.py module, for
instance during tests — manual or functional), no problem was shown,
and everything was working properly.

But at soon as somebody sees the "/" endpoint, the captcha was
required, by both the API and the `web.py` module.

This fixes it by adding a way to bypass the captcha with a new
`bypass_captcha` property on the form.
This commit is contained in:
Alexis Métaireau 2021-11-22 22:05:13 +01:00
parent 2adc2bf0be
commit 8c005af24a
3 changed files with 8 additions and 4 deletions

View file

@ -50,7 +50,7 @@ def need_auth(f):
class ProjectsHandler(Resource): class ProjectsHandler(Resource):
def post(self): def post(self):
form = ProjectForm(meta={"csrf": False}) form = ProjectForm(meta={"csrf": False}, bypass_captcha=True)
if form.validate() and current_app.config.get("ALLOW_PUBLIC_PROJECT_CREATION"): if form.validate() and current_app.config.get("ALLOW_PUBLIC_PROJECT_CREATION"):
project = form.save() project = form.save()
db.session.add(project) db.session.add(project)
@ -71,7 +71,7 @@ class ProjectHandler(Resource):
return "DELETED" return "DELETED"
def put(self, project): def put(self, project):
form = EditProjectForm(id=project.id, meta={"csrf": False}) form = EditProjectForm(id=project.id, meta={"csrf": False}, bypass_captcha=True)
if form.validate() and current_app.config.get("ALLOW_PUBLIC_PROJECT_CREATION"): if form.validate() and current_app.config.get("ALLOW_PUBLIC_PROJECT_CREATION"):
form.update(project) form.update(project)
db.session.commit() db.session.commit()

View file

@ -197,6 +197,10 @@ class ProjectForm(EditProjectForm):
password = PasswordField(_("Private code"), validators=[DataRequired()]) password = PasswordField(_("Private code"), validators=[DataRequired()])
submit = SubmitField(_("Create the project")) submit = SubmitField(_("Create the project"))
def __init__(self, *args, **kwargs):
self.bypass_captcha = kwargs.get('bypass_captcha', False)
super().__init__(*args, **kwargs)
def save(self): def save(self):
"""Create a new project with the information given by this form. """Create a new project with the information given by this form.
@ -232,12 +236,11 @@ class ProjectForm(EditProjectForm):
def enable_captcha(cls): def enable_captcha(cls):
captchaField = StringField( captchaField = StringField(
_("Which is a real currency: Euro or Petro dollar?"), _("Which is a real currency: Euro or Petro dollar?"),
validators=[DataRequired()],
) )
setattr(cls, "captcha", captchaField) setattr(cls, "captcha", captchaField)
def validate_captcha(form, field): def validate_captcha(form, field):
if not field.data.lower() == _("euro"): if not field.data.lower() == _("euro") and not form.bypass_captcha:
message = _("Please, validate the captcha to proceed.") message = _("Please, validate the captcha to proceed.")
raise ValidationError(Markup(message)) raise ValidationError(Markup(message))

View file

@ -286,6 +286,7 @@ class CaptchaTestCase(IhatemoneyTestCase):
assert len(models.Project.query.all()) == 1 assert len(models.Project.query.all()) == 1
def test_api_project_creation_does_not_need_captcha(self): def test_api_project_creation_does_not_need_captcha(self):
self.client.get('/')
resp = self.client.post( resp = self.client.post(
"/api/projects", "/api/projects",
data={ data={