New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a honeypot field to collections.add form to catch spammy bots (bug 1211012). #828
Add a honeypot field to collections.add form to catch spammy bots (bug 1211012). #828
Conversation
def clean(self): | ||
if self.cleaned_data['your_name']: | ||
raise forms.ValidationError( | ||
'You\'ve been flagged as spam, sorry about that.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used to think we had thoughts on strings re: \
in our style guide but I checked and we don't 😒
I always figured it was nicer to use double quotes for strings that would need escaping (eg "It's"
over 'It\'s'
), but if other olympia code uses \
then stick with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string should get passed through _
like in line 157.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this string is never intended to be read by an end user and never shown in the UI, but only to trip up bots, I said that localisation is not needed.
r+wc (Feel free to ignore my nitpick if using single-quotes is consistent with olympia--consistency is best!) |
Commit message is a bit too long. |
I updated the quotes, found other places where it's being used like that. |
@@ -143,6 +145,12 @@ def __init__(self, *args, **kw): | |||
self.instance.type in amo.COLLECTION_SPECIAL_SLUGS): | |||
del self.fields['slug'] | |||
|
|||
def clean(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could instead be done in clean_your_name
right? If you put it in clean
on purpose (to not have the error message associated with this field maybe? So it's not obvious that it's a honeypot?) then please add a comment here explaining that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't wanted it related to a field in the error messages so that it could be shown eventually at the top of the form in the __all__
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. So please add a comment explaining that ;) thanks!
This is nice and concise, I like it (and the tests are great). A small nitpick, then if you could squash your commits (yeah, I know), and we'll be able to merge ;) Thanks! r+wc |
@@ -136,6 +135,9 @@ class CollectionForm(ModelForm): | |||
icon = forms.FileField(label=_lazy(u'Icon'), | |||
required=False) | |||
|
|||
# This is just a honeypot field for bots to get caught | |||
your_name = forms.CharField(widget=forms.HiddenInput(), required=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think if this is just type="hidden" it will work as a honeypot field. It's likely to get ignored by a bot. Typically a honeypot field should be a normal field hidden with CSS. It should also be labelled in such a way to make sure people with assistive tech know to not fill it in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my experience it doesn't make any big difference for all the very dumb bots but assistive tech is a good point. display:none;
should cover this case completely too, does it not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd still want a label just to allow for the absolute worst case that CSS wasn't applied.
r- on the basis I'm not sure a hidden field will be likely to be effective on its own. |
@@ -143,6 +145,12 @@ def __init__(self, *args, **kw): | |||
self.instance.type in amo.COLLECTION_SPECIAL_SLUGS): | |||
del self.fields['slug'] | |||
|
|||
def clean(self): | |||
if self.cleaned_data['your_name']: | |||
raise forms.ValidationError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not want to raise a Validation error. It should probably look like a success and be quietly binned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd actually even raise a BadRequest or something in case it's filled out - a validation error was just the simplest way to go and avoid special-case handling in the view.
How'd you simply ignore this quietly? Just don't do anything and reload the form (as in clear all data and show an empty form again?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point is if you show an error you're making it obvious that the honeypot field was tripped. But if we're assuming that bots are super dumb then that won't matter necessarily. We should definitely instrument this so we know if it's catching anything at all.
Another consideration is to look at existing packages adding bolt-on honeypot field functionality. E.g. django-honeypot etc. (Not that I'm advocating any particular package). |
@muffinresearch existing packages do really weird stuff sometimes - specifically |
Maybe, it was merely a suggestion to consider prior art, in-case someone else has a solution that's been battle tested and already gone through iterations to improve it. |
Okay, unless I forgot something I made all changes discussed above. Ready for re-review :) |
@@ -143,6 +148,15 @@ def __init__(self, *args, **kw): | |||
self.instance.type in amo.COLLECTION_SPECIAL_SLUGS): | |||
del self.fields['slug'] | |||
|
|||
def clean(self): | |||
# Raise the honeypot validation error here to | |||
# keep it being rased in the __all__ section of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo raised
.
Not sure the sentence makes much sense (at least to me), maybe Check the honeypot here instead of 'clean_your_name' so the error message appears at the top of the form in the __all__ section
?
I think we're good to merge, if you could please first add some (graphite?) metrics, and then squash your commits? r+wc |
I wonder about this being just for this specific case? If we ever need another honeypot field it will require another custom implementation. If we think this is the only place we'll need it then perhaps this is fine rather than blocking on making it reusable. Fwiw I found the the honeypot field code that was used on the marketplace which is here: https://github.com/cvan/django-potato-captcha - see also https://github.com/mozilla/zamboni/search?p=1&q=potato&utf8=%E2%9C%93 (looks like it might have been extracted out separately). |
@muffinresearch yeah, I'll add statsd and then we'll see how it goes. If there's a need to add this to every form the existing code isn't that much so that it won't hurt to settle on another solution. I'd rather not integrate another dependency just now for these 8 lines of code. |
Sounds good |
a1d74eb
to
48f0713
Compare
Alright, added statsd integration. Ready for re-review 😃 |
lgtm r+ Thanks for the iterations! |
Oh and you'll want to squash the commits before you land it as before 👍 |
# This is just a honeypot field for bots to get caught | ||
your_name = forms.CharField( | ||
label=_lazy( | ||
u"Please don't fill out this field, it's used to catch bots"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you add a comment above this formatted like # L10n: bots is short for robots
then the localizers will see it in their web interface. It might help them out since English colloquialism can trip them up.
r+wc from me. Also, not mandatory, but as @mstriemer mentioned we tend to follow the git guidelines for commit messages. This helps a little when integrating with other tools. |
Squashed and merged in c348d57, thanks for the review! |
No description provided.