12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- import datetime
- import hashlib
- import logging
- import random
- import time
- from django.db import models
- from django.utils import timezone
- from django.utils.encoding import smart_str
- from captcha.conf import settings as captcha_settings
- # Heavily based on session key generation in Django
- # Use the system (hardware-based) random number generator if it exists.
- if hasattr(random, "SystemRandom"):
- randrange = random.SystemRandom().randrange
- else:
- randrange = random.randrange
- MAX_RANDOM_KEY = 18446744073709551616 # 2 << 63
- logger = logging.getLogger(__name__)
- class CaptchaStore(models.Model):
- id = models.AutoField(primary_key=True)
- challenge = models.CharField(blank=False, max_length=32)
- response = models.CharField(blank=False, max_length=32)
- hashkey = models.CharField(blank=False, max_length=40, unique=True)
- expiration = models.DateTimeField(blank=False)
- def save(self, *args, **kwargs):
- self.response = self.response.lower()
- if not self.expiration:
- self.expiration = timezone.now() + datetime.timedelta(
- minutes=int(captcha_settings.CAPTCHA_TIMEOUT)
- )
- if not self.hashkey:
- key_ = (
- smart_str(randrange(0, MAX_RANDOM_KEY))
- + smart_str(time.time())
- + smart_str(self.challenge, errors="ignore")
- + smart_str(self.response, errors="ignore")
- ).encode("utf8")
- self.hashkey = hashlib.sha1(key_).hexdigest()
- del key_
- super(CaptchaStore, self).save(*args, **kwargs)
- def __str__(self):
- return self.challenge
- def remove_expired(cls):
- cls.objects.filter(expiration__lte=timezone.now()).delete()
- remove_expired = classmethod(remove_expired)
- @classmethod
- def generate_key(cls, generator=None):
- challenge, response = captcha_settings.get_challenge(generator)()
- store = cls.objects.create(challenge=challenge, response=response)
- return store.hashkey
- @classmethod
- def pick(cls):
- if not captcha_settings.CAPTCHA_GET_FROM_POOL:
- return cls.generate_key()
- def fallback():
- logger.error("Couldn't get a captcha from pool, generating")
- return cls.generate_key()
- # Pick up a random item from pool
- minimum_expiration = timezone.now() + datetime.timedelta(
- minutes=int(captcha_settings.CAPTCHA_GET_FROM_POOL_TIMEOUT)
- )
- store = (
- cls.objects.filter(expiration__gt=minimum_expiration).order_by("?").first()
- )
- return (store and store.hashkey) or fallback()
- @classmethod
- def create_pool(cls, count=1000):
- assert count > 0
- while count > 0:
- cls.generate_key()
- count -= 1
|