Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions bedrock/mozorg/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ def render(self, name, value, attrs=None, renderer=None):
# semi-randomized in case we have more than one per page.
# this is maybe/probably overthought
honeypot_id = "office-fax-" + str(randrange(1001)) + "-" + str(datetime.now().strftime("%Y%m%d%H%M%S%f"))
tabindex_attr = 'tabindex="-1"'
return mark_safe(
'<div class="super-priority-field">'
'<label for="%s">%s</label>'
'<input type="text" name="office_fax" id="%s">'
"</div>" % (honeypot_id, honeypot_txt, honeypot_id)
'<input type="text" name="office_fax" id="%s" %s>'
"</div>" % (honeypot_id, honeypot_txt, honeypot_id, tabindex_attr)
)


Expand Down
9 changes: 8 additions & 1 deletion bedrock/newsletter/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from product_details import product_details

from bedrock.mozorg.forms import EmailInput, PrivacyWidget, strip_parenthetical
from bedrock.mozorg.forms import EmailInput, HoneyPotWidget, PrivacyWidget, strip_parenthetical
from bedrock.newsletter import utils
from lib.l10n_utils.fluent import ftl, ftl_lazy

Expand Down Expand Up @@ -186,6 +186,8 @@ class NewsletterFooterForm(forms.Form):
privacy = forms.BooleanField(widget=PrivacyWidget(attrs={"data-testid": "newsletter-privacy-checkbox"}))
source_url = forms.CharField(required=False)
newsletters = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple())
# office_fax is a honeypot field
office_fax = forms.CharField(widget=HoneyPotWidget(attrs={"tabindex": "-1"}), required=False, empty_value="")

# has to take a newsletters argument so it can figure
# out which languages to list in the form.
Expand Down Expand Up @@ -251,6 +253,11 @@ def clean_source_url(self):

return su

def clean_office_fax(self):
honeypot = self.cleaned_data.pop("office_fax", None)
if honeypot:
raise forms.ValidationError("Your submission could not be processed")


class EmailForm(forms.Form):
"""
Expand Down
3 changes: 3 additions & 0 deletions bedrock/newsletter/templates/newsletter/includes/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
{% endif %}
<input type="hidden" name="source_url" value="{{ request.build_absolute_uri() }}">

{# Honeypot field #}
{{ form.office_fax|safe }}

{% if include_title and is_multi_newsletter_form %}
<header class="mzp-c-newsletter-header">
<h3 class="mzp-c-newsletter-title">{{ title|d(ftl('multi-newsletter-form-title'), true) }}</h3>
Expand Down
25 changes: 25 additions & 0 deletions bedrock/newsletter/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,28 @@ def test_multiple_newsletters(self):
form = NewsletterFooterForm(spacey_newsletters, "en-US", data=data.copy())
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data["newsletters"], newsletters)

def test_honeypot_empty_valid(self):
"""Honeypot field should be valid when empty"""
data = {
"email": "[email protected]",
"lang": "fr",
"privacy": True,
"newsletters": [self.newsletter_name],
"office_fax": "", # honeypot field
}
form = NewsletterFooterForm(self.newsletter_name, locale="en-US", data=data.copy())
self.assertTrue(form.is_valid(), form.errors)

def test_honeypot_filled_invalid(self):
"""Honeypot field should be invalid when filled"""
data = {
"email": "[email protected]",
"lang": "fr",
"privacy": True,
"newsletters": [self.newsletter_name],
"office_fax": "some value", # honeypot field
}
form = NewsletterFooterForm(self.newsletter_name, locale="en-US", data=data.copy())
self.assertFalse(form.is_valid())
self.assertIn("office_fax", form.errors)
3 changes: 3 additions & 0 deletions bedrock/newsletter/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ def newsletter_subscribe(request):
errors.append(ftl("newsletter-form-please-enter-a-valid"))
if "privacy" in form.errors:
errors.append(ftl("newsletter-form-you-must-agree-to"))
if "office_fax" in form.errors:
# Honeypot field was filled
errors.append(ftl("newsletter-form-we-are-sorry-but-there"))
for fieldname in ("newsletters", "lang", "country"):
if fieldname in form.errors:
errors.extend(form.errors[fieldname])
Expand Down
17 changes: 16 additions & 1 deletion media/css/protocol/components/newsletter-form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,19 @@ $image-path: '/media/protocol/img';
}
}

/* stylelint-enable declaration-no-important */
// Honeypot field styling - hide from users but keep accessible to bots
.super-priority-field {
position: absolute !important;
left: -9999px !important;
top: -9999px !important;
width: 1px !important;
height: 1px !important;
overflow: hidden !important;
opacity: 0 !important;
pointer-events: none !important;

// Hide from screen readers
label {
display: none !important;
}
}