bgneal@472
|
1 """
|
bgneal@472
|
2 This module contains decorators for the antispam application.
|
bgneal@472
|
3
|
bgneal@472
|
4 """
|
bgneal@472
|
5 from datetime import timedelta
|
bgneal@472
|
6 from functools import wraps
|
bgneal@472
|
7
|
bgneal@472
|
8 from django.shortcuts import render
|
bgneal@505
|
9 from django.utils import simplejson
|
bgneal@472
|
10
|
bgneal@473
|
11 from antispam.rate_limit import RateLimiter, RateLimiterUnavailable
|
bgneal@472
|
12
|
bgneal@472
|
13
|
bgneal@472
|
14 def rate_limit(count=10, interval=timedelta(minutes=1),
|
bgneal@472
|
15 lockout=timedelta(hours=8)):
|
bgneal@472
|
16
|
bgneal@472
|
17 def decorator(fn):
|
bgneal@472
|
18
|
bgneal@472
|
19 @wraps(fn)
|
bgneal@472
|
20 def wrapped(request, *args, **kwargs):
|
bgneal@472
|
21
|
bgneal@473
|
22 ip = request.META.get('REMOTE_ADDR')
|
bgneal@473
|
23 try:
|
bgneal@473
|
24 rate_limiter = RateLimiter(ip, count, interval, lockout)
|
bgneal@479
|
25 if rate_limiter.is_blocked():
|
bgneal@479
|
26 return render(request, 'antispam/blocked.html', status=403)
|
bgneal@479
|
27
|
bgneal@473
|
28 except RateLimiterUnavailable:
|
bgneal@473
|
29 # just call the function and return the result
|
bgneal@473
|
30 return fn(request, *args, **kwargs)
|
bgneal@473
|
31
|
bgneal@472
|
32 response = fn(request, *args, **kwargs)
|
bgneal@472
|
33
|
bgneal@472
|
34 if request.method == 'POST':
|
bgneal@505
|
35
|
bgneal@505
|
36 # Figure out if the view succeeded; if it is a non-ajax view,
|
bgneal@505
|
37 # then success means a redirect is about to occur. If it is
|
bgneal@505
|
38 # an ajax view, we have to decode the json response.
|
bgneal@505
|
39 success = False
|
bgneal@505
|
40 if not request.is_ajax():
|
bgneal@505
|
41 success = (response and response.has_header('location') and
|
bgneal@505
|
42 response.status_code == 302)
|
bgneal@505
|
43 elif response:
|
bgneal@505
|
44 json_resp = simplejson.loads(response.content)
|
bgneal@505
|
45 success = json_resp['success']
|
bgneal@505
|
46
|
bgneal@505
|
47 if not success:
|
bgneal@505
|
48 try:
|
bgneal@505
|
49 blocked = rate_limiter.incr()
|
bgneal@505
|
50 except RateLimiterUnavailable:
|
bgneal@505
|
51 blocked = False
|
bgneal@505
|
52
|
bgneal@505
|
53 if blocked:
|
bgneal@479
|
54 return render(request, 'antispam/blocked.html', status=403)
|
bgneal@479
|
55
|
bgneal@472
|
56 return response
|
bgneal@472
|
57
|
bgneal@472
|
58 return wrapped
|
bgneal@472
|
59 return decorator
|