Source

django-doorkeeper / doorkeeper / views.py

Full commit
# Create your views here.
from django.http import Http404

from models import BotRecord
import datetime
from django.conf import settings
import hashlib
from utils import MemClient
try:
    from django.utils.timezone import now as django_now
except ImportError:
    django_now=datetime.datetime.now


import logging
log = logging.getLogger(__name__)

TERM = getattr(settings,'DOORKEEPER_TERM', 1200)
PATIENCE= getattr(settings,'DOORKEEPER_PATIENCE', 5)
MEMCACHE=getattr(settings,'DOORKEEPER_MEMCACHE', False)

def inspect(request):
    """

    View to register suspicious client and raise Http404
    if bad request frequency is higher then PATIENCE.
    Counter BotRecord.penalty_count increases until threshold.
    Then detention_upto is set to future and middleware begins bouncing
    this client.
    Ksi variable = minimum interval for next request (humans should be slow! :)
    """
    sagent = request.META.get('HTTP_USER_AGENT',"n/a")
    saddr = request.META.get('REMOTE_ADDR',"n/a")
    shash = "%s %s"% (saddr, sagent)
    dd    = hashlib.md5()
    dd.update(shash)
    memhash = dd.hexdigest()
    memhash0= memhash+"0"
    bd=0
    ksi  = datetime.timedelta(0,2)
    now  = django_now()
    try:
        if MEMCACHE:
            mc = MemClient(MEMCACHE)
            bd = mc.get(memhash0)
            """
            if-block below is for massive malicious request attack. The goal is
            to record in memcache variable bd as soon as possible for next
            instance of this view.
            """
            if bd is None:
                bd=1
                mc.add(memhash0,bd,TERM)
            else:
                bd+=1
                mc.set(memhash0,bd)
            br = mc.get(memhash)

            if br is None:
                br = BotRecord.objects.get(bot_hash=shash)
                mc.add(memhash,br,time=TERM*2)
            else:
                br.penalty_count=bd
                mc.set(memhash,br)
        else:
            br = BotRecord.objects.get(bot_hash=shash)
        delta= datetime.timedelta(0,TERM)
        if br.last_date+delta > now:
            br.penalty_count+=1
            if br.penalty_count > PATIENCE:
                br.detention_upto=now+delta
                br.jail_count+=1
            else:
                br.detention_upto=now+ksi;
        else:
            if br.penalty_count > PATIENCE:  # for old banned client
                br.penalty_count-=PATIENCE   # forgiving them partly
    except BotRecord.DoesNotExist:
        br=BotRecord.objects.create(bot_hash=shash,bot_name=sagent, bot_adr=saddr,
                                      detention_upto=now+ksi,penalty_count=1)
    if (bd > 1) and (bd > br.penalty_count) : br.penalty_count=bd
    br.save()
    if MEMCACHE:
        mc.set(memhash,br)
        log.info("path:%s Memcached view %s, penalty %s, detention %s" %
                 (request.path, shash,br.penalty_count,br.detention_upto))
    raise Http404()