Skip to content

[Bug 785850] Limit votes on answers and questions #1217

Closed
wants to merge 2 commits into from

3 participants

@mythmon
Mozilla member
mythmon commented Mar 20, 2013

Limit votes on answers and questions to 10 votes per day of either type. Votes after the limit of 10 will be silently ignored. The limit is based on IP addresses for unauthenticated users, or user id for authenticated users. Authenticated users are not limited by IP at all.

The tests are kind of complicated, but they work. The alternative is somehow trying to make the rate limits different during tests, which I'm not really excited about.

r?

@mythmon mythmon [Bug 785850] Limit votes on answers and questions
Limit votes on answers and questions to 10 votes per day of either type.
Votes after the limit of 10 will be silently ignored. The limit is based
on IP addresses for unauthenticated users, or user id for authenticated
users. Authenticatd users are not limited by IP at all.
1a8c397
@rlr rlr commented on the diff Mar 20, 2013
apps/questions/views.py
@@ -714,6 +715,7 @@ def unsolve(request, question_id, answer_id):
@require_POST
@csrf_exempt
+@ratelimit(keys=user_or_ip, ip=False, rate='10/d')
@rlr
Mozilla member
rlr added a note Mar 20, 2013

What does ip=False mean? Is that just overriden by user_or_ip?

@mythmon
Mozilla member
mythmon added a note Mar 20, 2013

By default django-ratelimit will limit based on IP. ip=False disables that default, so it only uses user_or_ip.

@jsocol
Mozilla member
jsocol added a note Mar 20, 2013

I'm thinking the next rev adds settings to set project defaults for these things.

@mythmon
Mozilla member
mythmon added a note Mar 21, 2013

Ooh, that's a good idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rlr rlr and 2 others commented on an outdated diff Mar 20, 2013
apps/sumo/utils.py
@@ -165,3 +165,18 @@ def truncated_json_dumps(obj, max_length, key, ensure_ascii=False):
"`max_length`.")
dupe[key] = dupe[key][:-diff]
return json.dumps(dupe, ensure_ascii=ensure_ascii)
+
+
+def user_or_ip(request):
+ """Used for generating rate limiting keys. Returns IP address for
+ anonymous users, and pks for authenticated users.
+
+ Examples
+ Anonymous: 'uip:127.0.0.1'
+ Authenticated: 'uip:17859'
+ """
+ if hasattr(request, 'user') and request.user.is_authenticated():
+ key = str(request.user.pk)
+ else:
+ key = request.META['REMOTE_ADDR']
@rlr
Mozilla member
rlr added a note Mar 20, 2013

I'm pretty sure you want HTTP_X_FORWARDED_FOR here. At least in prod. So maybe you want to do something like:
request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('request.REMOTE_ADDR')).

See https://support.mozilla.org/admin/env for full WSGI request details on prod, for example.

@rlr
Mozilla member
rlr added a note Mar 20, 2013

The reason is that in prod, REMOTE_ADDR will have the load balancer IP address. Does this sound right @jsocol ^^ ?

@mythmon
Mozilla member
mythmon added a note Mar 20, 2013

That matches what I see on that env page. I'll fix that.

@jsocol
Mozilla member
jsocol added a note Mar 20, 2013

We don't want to trust X-Forwarded-For unless we're validating it. (Clients can set it, and it can be a list.) We haved SetRemoteAddressFromForwardedFor middleware somewhere. That never worked because it implemented (or tried to, anyway) a complicated algorithm that was supposed to work with our specific set up.

Let's talk to IT and see if we can trust X_CLUSTER_CLIENT_IP or X_FORWARDED_FOR. It's possible that the rules have changed since Dave first walked me through that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rlr
Mozilla member
rlr commented Mar 20, 2013

I like the decorator!

@mythmon
Mozilla member
mythmon commented Mar 20, 2013

James did the heavy lifting, writing django-ratelimit, and modifying it recently. I just stuck it in :)

@mythmon
Mozilla member
mythmon commented Mar 20, 2013

feedback^

@rlr
Mozilla member
rlr commented Mar 21, 2013

LGTM. I used the Modify Headers addon to add a HTTP_X_FORWARDED_FOR to the request and try to trick the proxy but it passed on the right value to the app. R+

@rlr
Mozilla member
rlr commented Mar 21, 2013

DOH! I should've tested passing X_FORWARDED_FOR. That one keeps the value you pass in the request. But if I pass X_CLUSTER_CLIENT_IP it is overriden with the right value.

@rlr
Mozilla member
rlr commented Mar 21, 2013
@rlr rlr closed this Mar 21, 2013
@mythmon mythmon deleted the mythmon:rate-limit-question-votes-785850 branch Mar 21, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.