Skip to content
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

Conversation

EnTeQuAk
Copy link
Contributor

No description provided.

def clean(self):
if self.cleaned_data['your_name']:
raise forms.ValidationError(
'You\'ve been flagged as spam, sorry about that.')
Copy link
Contributor

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.

Copy link
Contributor

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.

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.

@tofumatt
Copy link
Contributor

r+wc (Feel free to ignore my nitpick if using single-quotes is consistent with olympia--consistency is best!)

@mstriemer
Copy link
Contributor

Commit message is a bit too long.

@EnTeQuAk
Copy link
Contributor Author

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):
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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!

@magopian
Copy link
Contributor

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)
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

@muffinresearch
Copy link
Contributor

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(
Copy link
Contributor

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.

Copy link
Contributor Author

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?)

Copy link
Contributor

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.

@muffinresearch
Copy link
Contributor

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).

@EnTeQuAk
Copy link
Contributor Author

@muffinresearch existing packages do really weird stuff sometimes - specifically django-honeypot is imho way to overkill for a simple honeypot field.

@muffinresearch
Copy link
Contributor

@muffinresearch existing packages do really weird stuff sometimes - specifically django-honeypot is imho way to overkill for a simple honeypot field.

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.

@EnTeQuAk
Copy link
Contributor Author

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
Copy link
Contributor

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?

@magopian
Copy link
Contributor

I think we're good to merge, if you could please first add some (graphite?) metrics, and then squash your commits?

r+wc

@muffinresearch
Copy link
Contributor

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).

@EnTeQuAk
Copy link
Contributor Author

@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.

@muffinresearch
Copy link
Contributor

Sounds good

@EnTeQuAk EnTeQuAk force-pushed the feature/add-honeypot-to-collections-add branch from a1d74eb to 48f0713 Compare October 22, 2015 18:04
@EnTeQuAk
Copy link
Contributor Author

Alright, added statsd integration. Ready for re-review 😃

@muffinresearch
Copy link
Contributor

lgtm r+

Thanks for the iterations!

@muffinresearch
Copy link
Contributor

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"),
Copy link
Contributor

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.

@kumar303
Copy link
Contributor

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.

@EnTeQuAk
Copy link
Contributor Author

Squashed and merged in c348d57, thanks for the review!

@EnTeQuAk EnTeQuAk closed this Oct 26, 2015
@EnTeQuAk EnTeQuAk deleted the feature/add-honeypot-to-collections-add branch November 12, 2015 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants