1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 23:48:47 +00:00

Update captcha

This commit is contained in:
zhengxie
2014-08-05 14:41:04 +08:00
parent 10ea577fb2
commit 2dd360e5e7
31 changed files with 339 additions and 100 deletions

View File

@@ -1,6 +1,6 @@
import re
VERSION = (0, 4, 0)
VERSION = (0, 4, 3)
def get_version(svn=False):
@@ -20,8 +20,8 @@ def pillow_required():
except ImportError:
try:
import Image
import ImageDraw
import ImageFont
import ImageDraw # NOQA
import ImageFont # NOQA
except ImportError:
return True

View File

@@ -1,6 +1,5 @@
import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
CAPTCHA_FONT_PATH = getattr(settings, 'CAPTCHA_FONT_PATH', os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'fonts/Vera.ttf')))
CAPTCHA_FONT_SIZE = getattr(settings, 'CAPTCHA_FONT_SIZE', 22)
@@ -19,9 +18,9 @@ CAPTCHA_IMAGE_BEFORE_FIELD = getattr(settings, 'CAPTCHA_IMAGE_BEFORE_FIELD', Tru
CAPTCHA_DICTIONARY_MIN_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MIN_LENGTH', 0)
CAPTCHA_DICTIONARY_MAX_LENGTH = getattr(settings, 'CAPTCHA_DICTIONARY_MAX_LENGTH', 99)
if CAPTCHA_IMAGE_BEFORE_FIELD:
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', u'%(image)s %(hidden_field)s %(text_field)s')
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', '%(image)s %(hidden_field)s %(text_field)s')
else:
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', u'%(hidden_field)s %(text_field)s %(image)s')
CAPTCHA_OUTPUT_FORMAT = getattr(settings, 'CAPTCHA_OUTPUT_FORMAT', '%(hidden_field)s %(text_field)s %(image)s')
CAPTCHA_TEST_MODE = getattr(settings, 'CAPTCHA_TEST_MODE', getattr(settings, 'CATPCHA_TEST_MODE', False))

View File

@@ -1,5 +1,4 @@
from captcha.conf import settings
from django.conf import settings as django_settings
from captcha.models import CaptchaStore, get_safe_now
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse, NoReverseMatch
@@ -7,6 +6,7 @@ from django.forms import ValidationError
from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import TextInput, MultiWidget, HiddenInput
from django.utils.translation import ugettext, ugettext_lazy
from six import u
class BaseCaptchaTextInput(MultiWidget):
@@ -38,14 +38,10 @@ class BaseCaptchaTextInput(MultiWidget):
key = CaptchaStore.generate_key()
# these can be used by format_output and render
self._value = [key, u'']
self._value = [key, u('')]
self._key = key
self.id_ = self.build_attrs(attrs).get('id', None)
def render(self, name, value, attrs=None):
#self.fetch_captcha_store(name, value, attrs)
return super(BaseCaptchaTextInput, self).render(name, self._value, attrs=attrs)
def id_for_label(self, id_):
if id_:
return id_ + '_1'
@@ -76,6 +72,7 @@ class CaptchaTextInput(BaseCaptchaTextInput):
def format_output(self, rendered_widgets):
hidden_field, text_field = rendered_widgets
text_field = text_field.replace('<input', '<input autocomplete="off"')
return self._args['output_format'] % {
'image': self.image_and_audio,
'hidden_field': hidden_field,
@@ -88,8 +85,6 @@ class CaptchaTextInput(BaseCaptchaTextInput):
self.image_and_audio = '<img src="%s" alt="captcha" class="captcha" />' % self.image_url()
if settings.CAPTCHA_FLITE_PATH:
self.image_and_audio = '<a href="%s" title="%s">%s</a>' % (self.audio_url(), ugettext('Play CAPTCHA as audio file'), self.image_and_audio)
return super(CaptchaTextInput, self).render(name, self._value, attrs=attrs)

View File

@@ -2,6 +2,7 @@
import random
from captcha.conf import settings
from django.core.urlresolvers import reverse
from six import u
def math_challenge():
@@ -15,14 +16,14 @@ def math_challenge():
def random_char_challenge():
chars, ret = u'abcdefghijklmnopqrstuvwxyz', u''
chars, ret = u('abcdefghijklmnopqrstuvwxyz'), u('')
for i in range(settings.CAPTCHA_LENGTH):
ret += random.choice(chars)
return ret.upper(), ret
def unicode_challenge():
chars, ret = u'äàáëéèïíîöóòüúù', u''
chars, ret = u('äàáëéèïíîöóòüúù'), u('')
for i in range(settings.CAPTCHA_LENGTH):
ret += random.choice(chars)
return ret.upper(), ret
@@ -70,6 +71,10 @@ def noise_dots(draw, image):
return draw
def noise_null(draw, image):
return draw
def post_smooth(image):
try:
import ImageFilter

View File

@@ -0,0 +1,31 @@
# django-simple-captcha Bulgarian translation
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the django-simple-captcha package.
# Venelin Stoykov <vkstoykov@gmail.com>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.4.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-10 14:43+0200\n"
"PO-Revision-Date: 2014-02-10 15:00+0200\n"
"Last-Translator: Venelin Stoykov <vkstoykov@gmail.com>\n"
"Language-Team: bg <vkstoykov@gmail.com>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: fields.py:91
msgid "Play CAPTCHA as audio file"
msgstr "Чуй текста като аудио файл"
#: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Сгрешен текст"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Това поле е задължително"

View File

@@ -11,7 +11,7 @@ msgstr ""
"PO-Revision-Date: 2012-10-09 07:08+0200\n"
"Last-Translator: Beda Kosata <bedrich.kosata@nic.cz>\n"
"Language-Team: Czech <>\n"
"Language: \n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -11,6 +11,7 @@ msgstr ""
"PO-Revision-Date: 2013-07-16 12:10+0100\n"
"Last-Translator: Patrick Lauber <patrick.lauber@divio.ch>\n"
"Language-Team: DE <digi@treepy.com>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-16 12:06+0200\n"
"PO-Revision-Date: 2014-05-20 21:22+0100\n"
"Last-Translator: https://github.com/dragosdobrota\n"
"Language-Team: es\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.6.5\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "Reproducir CAPTCHA de audio"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "CAPTCHA no válido"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Este campo es obligatorio."

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package.
# Patrick Samson <maxcom@laposte.net>, 2010.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.2.0\n"
@@ -11,8 +10,8 @@ msgstr ""
"POT-Creation-Date: 2012-07-25 11:44+0300\n"
"PO-Revision-Date: 2010-09-16 12:16+0200\n"
"Last-Translator: Patrick Samson <maxcom@laposte.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"Language-Team: fr <maxcom@laposte.net>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package.
# Arjuna Del Toso <stupidate@gmail.net>, 2012
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
@@ -12,6 +11,8 @@ msgstr ""
"PO-Revision-Date: 2012-11-14 02:53+0000\n"
"Last-Translator: Arjuna Del Toso <stupidate@gmail.com>\n"
"MIME-Version: 1.0\n"
"Language-Team: Arjuna Del Toso <stupidate@gmail.com>\n"
"Language: it\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"

View File

@@ -0,0 +1,31 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Keisuke URAGO <bravo@resourcez.org>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-13 07:11+0900\n"
"PO-Revision-Date: 2014-02-13 07:11+0900\n"
"Last-Translator: Keisuke URAGO <bravo@resourcez.org>\n"
"Language-Team: Keisuke URAGO <bravo@resourcez.org>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "CAPTCHAをオーディオで読み上げる"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "CAPTCHAの値が違っています"
#: tests/tests.py:125
msgid "This field is required."
msgstr "この項目は必須です"

View File

@@ -3,15 +3,16 @@
# This file is distributed under the same license as the PACKAGE package.
# Leon de Rijke <leon@cmsworks.nl>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-15 13:26+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2013-02-15 13:26+0100\n"
"Last-Translator: Leon de Rijke <leon@cmsworks.nl>\n"
"MIME-Version: 1.0\n"
"Language-Team: Leon de Rijke <leon@cmsworks.nl>\n"
"Language: nl\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"

View File

@@ -3,16 +3,15 @@
# This file is distributed under the same license as the django-simple-captcha package.
# Sławomir Zborowski <slawomir.zborowski@hotmail.com>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-18 18:49+0200\n"
"PO-Revision-Date: 2013-08-18 18:52+0200\n"
"Last-Translator: Sławomir Zborowski <slawomir.zborowski@hotmail.com>\n"
"Language-Team: Polisch\n"
"Language: \n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package.
# Alisson Patricio <eu@alisson.net>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.7\n"
@@ -11,7 +10,8 @@ msgstr ""
"POT-Creation-Date: 2013-05-18 10:58-0300\n"
"PO-Revision-Date: 2013-05-18 13:12-0300\n"
"Last-Translator: Alisson Patricio <eu@alisson.net>\n"
"Language: Portuguese (Brazilian)\n"
"Language-Team: Alisson Patricio <eu@alisson.net>\n"
"Language: pt_br\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -3,16 +3,15 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Project-Id-Version: django-simple-captcha 0.3.7\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-07-25 11:17+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"PO-Revision-Date: 2012-07-25 11:17+0300\n"
"Last-Translator: \n"
"Language-Team: ru <LL@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# Slovak translation of django-simple-captcha.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Pavol Otto <pavol.otto@nic.cz>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.7\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-15 17:16+0200\n"
"PO-Revision-Date: 2013-10-15 17:16+0200\n"
"Last-Translator: Pavol Otto <pavol.otto@nic.cz>\n"
"Language-Team: SK\n"
"Language: sk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: fields.py:90
msgid "Play CAPTCHA as audio file"
msgstr "Prehrať captchu ako audio súbor"
#: fields.py:105 fields.py:134 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Neplatná CAPTCHA"
#: tests/tests.py:125
msgid "This field is required."
msgstr "Toto pole je povinné."

View File

@@ -3,7 +3,6 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
@@ -11,7 +10,8 @@ msgstr ""
"POT-Creation-Date: 2013-01-19 16:33-0200\n"
"PO-Revision-Date: 2013-01-19 20:52+0200\n"
"Last-Translator: Gokmen Gorgen <gokmen@alageek.com>\n"
"Language: \n"
"Language-Team: TR Gokmen Gorgen <gokmen@alageek.com>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -0,0 +1,32 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-02-21 22:05+0200\n"
"PO-Revision-Date: 2014-02-21 22:05+0200\n"
"Last-Translator: @FuriousCoder\n"
"Language-Team: uk @FuriousCoder\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: fields.py:91
msgid "Play CAPTCHA as audio file"
msgstr "Відтворити CAPTCHA як аудіо файл."
#: fields.py:106 fields.py:135 tests/tests.py:99 tests/tests.py:239
#: tests/tests.py:246
msgid "Invalid CAPTCHA"
msgstr "Неправильна відповідь."
#: tests/tests.py:125
msgid "This field is required."
msgstr "Це поле є обов'язковим."

View File

@@ -3,15 +3,15 @@
# This file is distributed under the same license as the PACKAGE package.
# Ming Chen <c.ming@live.com>, 2013.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-simple-captcha 0.3.6\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-03-01 05:04+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: 2013-03-01 05:04+0800\n"
"Last-Translator: Ming Chen <c.ming@live.com>\n"
"Language: \n"
"Language-Team: zh_cn Ming Chen <c.ming@live.com>\n"
"Language: zh_cn\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -11,15 +11,15 @@ class Command(BaseCommand):
verbose = int(options.get('verbosity'))
expired_keys = CaptchaStore.objects.filter(expiration__lte=get_safe_now()).count()
if verbose >= 1:
print "Currently %d expired hashkeys" % expired_keys
print("Currently %d expired hashkeys" % expired_keys)
try:
CaptchaStore.remove_expired()
except:
if verbose >= 1:
print "Unable to delete expired hashkeys."
print("Unable to delete expired hashkeys.")
sys.exit(1)
if verbose >= 1:
if expired_keys > 0:
print "%d expired hashkeys removed." % expired_keys
print("%d expired hashkeys removed." % expired_keys)
else:
print "No keys to remove."
print("No keys to remove.")

View File

@@ -1,39 +1,26 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'CaptchaStore'
db.create_table('captcha_captchastore', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('challenge', self.gf('django.db.models.fields.CharField')(max_length=32)),
('response', self.gf('django.db.models.fields.CharField')(max_length=32)),
('hashkey', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)),
('expiration', self.gf('django.db.models.fields.DateTimeField')()),
))
db.send_create_signal('captcha', ['CaptchaStore'])
from django.db import models, migrations
def backwards(self, orm):
class Migration(migrations.Migration):
# Deleting model 'CaptchaStore'
db.delete_table('captcha_captchastore')
dependencies = [
]
models = {
'captcha.captchastore': {
'Meta': {'object_name': 'CaptchaStore'},
'challenge': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'expiration': ('django.db.models.fields.DateTimeField', [], {}),
'hashkey': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'response': ('django.db.models.fields.CharField', [], {'max_length': '32'})
}
}
complete_apps = ['captcha']
operations = [
migrations.CreateModel(
name='CaptchaStore',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('challenge', models.CharField(max_length=32)),
('response', models.CharField(max_length=32)),
('hashkey', models.CharField(unique=True, max_length=40)),
('expiration', models.DateTimeField()),
],
options={
},
bases=(models.Model,),
),
]

View File

@@ -0,0 +1,21 @@
"""
Django migrations for django-simple-captcha app
This package does not contain South migrations. South migrations can be found
in the ``south_migrations`` package.
"""
SOUTH_ERROR_MESSAGE = """\n
For South support, customize the SOUTH_MIGRATION_MODULES setting like so:
SOUTH_MIGRATION_MODULES = {
'captcha': 'captcha.south_migrations',
}
"""
# Ensure the user is not using Django 1.6 or below with South
try:
from django.db import migrations # noqa
except ImportError:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured(SOUTH_ERROR_MESSAGE)

View File

@@ -40,10 +40,9 @@ class CaptchaStore(models.Model):
expiration = models.DateTimeField(blank=False)
def save(self, *args, **kwargs):
#import ipdb; ipdb.set_trace()
self.response = six.text_type(self.response).lower()
if not self.expiration:
#self.expiration = datetime.datetime.now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT))
self.expiration = get_safe_now() + datetime.timedelta(minutes=int(captcha_settings.CAPTCHA_TIMEOUT))
if not self.hashkey:
key_ = unicodedata.normalize('NFKD', str(randrange(0, MAX_RANDOM_KEY)) + str(time.time()) + six.text_type(self.challenge)).encode('ascii', 'ignore') + unicodedata.normalize('NFKD', six.text_type(self.response)).encode('ascii', 'ignore')

View File

@@ -0,0 +1,39 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'CaptchaStore'
db.create_table('captcha_captchastore', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('challenge', self.gf('django.db.models.fields.CharField')(max_length=32)),
('response', self.gf('django.db.models.fields.CharField')(max_length=32)),
('hashkey', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)),
('expiration', self.gf('django.db.models.fields.DateTimeField')()),
))
db.send_create_signal('captcha', ['CaptchaStore'])
def backwards(self, orm):
# Deleting model 'CaptchaStore'
db.delete_table('captcha_captchastore')
models = {
'captcha.captchastore': {
'Meta': {'object_name': 'CaptchaStore'},
'challenge': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'expiration': ('django.db.models.fields.DateTimeField', [], {}),
'hashkey': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'response': ('django.db.models.fields.CharField', [], {'max_length': '32'})
}
}
complete_apps = ['captcha']

View File

@@ -1 +1 @@
from .tests import CaptchaCase, trivial_challenge
from .tests import CaptchaCase, trivial_challenge # NOQA

View File

@@ -12,6 +12,7 @@ import json
import re
import six
import os
from six import u
class CaptchaCase(TestCase):
@@ -42,7 +43,6 @@ class CaptchaCase(TestCase):
settings.CAPTCHA_WORDS_DICTIONARY = self.__current_settings_dictionary
settings.CAPTCHA_PUNCTUATION = self.__current_settings_punctuation
def __extract_hash_and_response(self, r):
hash_ = re.findall(r'value="([0-9a-f]+)"', str(r.content))[0]
response = CaptchaStore.objects.get(hashkey=hash_).response
@@ -175,7 +175,7 @@ class CaptchaCase(TestCase):
def testOutputFormat(self):
for urlname in ('captcha-test', 'captcha-test-model-form'):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s<p>Hello, captcha world</p>%(hidden_field)s%(text_field)s'
settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s<p>Hello, captcha world</p>%(hidden_field)s%(text_field)s')
r = self.client.get(reverse(urlname))
self.assertEqual(r.status_code, 200)
self.assertTrue('<p>Hello, captcha world</p>' in str(r.content))
@@ -186,7 +186,7 @@ class CaptchaCase(TestCase):
# we turn on DEBUG because CAPTCHA_OUTPUT_FORMAT is only checked debug
django_settings.DEBUG = True
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s'
settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s')
try:
self.client.get(reverse(urlname))
self.fail()
@@ -195,14 +195,14 @@ class CaptchaCase(TestCase):
django_settings.DEBUG = __current_settings_debug
def testPerFormFormat(self):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s testCustomFormatString %(hidden_field)s %(text_field)s'
settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s testCustomFormatString %(hidden_field)s %(text_field)s')
r = self.client.get(reverse('captcha-test'))
self.assertTrue('testCustomFormatString' in str(r.content))
r = self.client.get(reverse('test_per_form_format'))
self.assertTrue('testPerFieldCustomFormatString' in str(r.content))
def testIssue31ProperLabel(self):
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s %(hidden_field)s %(text_field)s'
settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s %(hidden_field)s %(text_field)s')
r = self.client.get(reverse('captcha-test'))
self.assertTrue('<label for="id_captcha_1"' in str(r.content))
@@ -226,7 +226,7 @@ class CaptchaCase(TestCase):
This test covers a default django field and widget behavior
It not assert anything. If something is wrong it will raise a error!
"""
settings.CAPTCHA_OUTPUT_FORMAT = u'%(image)s %(hidden_field)s %(text_field)s'
settings.CAPTCHA_OUTPUT_FORMAT = u('%(image)s %(hidden_field)s %(text_field)s')
widget = CaptchaTextInput(attrs={'class': 'required'})
CaptchaField(widget=widget)
@@ -270,11 +270,30 @@ class CaptchaCase(TestCase):
self.assertEqual(r.status_code, 200)
hash_, response = self.__extract_hash_and_response(r)
r = self.client.post(reverse('captcha-test-non-required'), dict(captcha_0=hash_, captcha_1=response, subject='xxx', sender='asasd@asdasd.com'))
self.assertEqual(r.status_code, 200)
self.assertTrue(str(r.content).find('Form validated') > 0)
def test_autocomplete_off(self):
r = self.client.get(reverse('captcha-test'))
self.assertTrue('<input autocomplete="off" ' in six.text_type(r.content))
def test_autocomplete_not_on_hidden_input(self):
r = self.client.get(reverse('captcha-test'))
self.assertFalse('autocomplete="off" type="hidden" name="captcha_0"' in six.text_type(r.content))
self.assertFalse('autocomplete="off" id="id_captcha_0" name="captcha_0" type="hidden"' in six.text_type(r.content))
def test_transparent_background(self):
__current_test_mode_setting = settings.CAPTCHA_BACKGROUND_COLOR
settings.CAPTCHA_BACKGROUND_COLOR = "transparent"
for key in [store.hashkey for store in six.itervalues(self.stores)]:
response = self.client.get(reverse('captcha-image', kwargs=dict(key=key)))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.has_header('content-type'))
self.assertEqual(response._headers.get('content-type'), ('Content-Type', 'image/png'))
settings.CAPTCHA_BACKGROUND_COLOR = __current_test_mode_setting
def trivial_challenge():
return 'trivial', 'trivial'

View File

@@ -3,7 +3,8 @@ try:
except ImportError:
from django.conf.urls.defaults import url, patterns, include
urlpatterns = patterns('',
urlpatterns = patterns(
'',
url(r'test/$', 'captcha.tests.views.test', name='captcha-test'),
url(r'test-modelform/$', 'captcha.tests.views.test_model_form', name='captcha-test-model-form'),
url(r'test2/$', 'captcha.tests.views.test_custom_error_message', name='captcha-test-custom-error-message'),

View File

@@ -3,7 +3,7 @@ from captcha.fields import CaptchaField
from django.template import RequestContext, loader
from django.http import HttpResponse
from django.contrib.auth.models import User
from six import u
TEST_TEMPLATE = r'''
{% load url from future %}
@@ -30,6 +30,7 @@ TEST_TEMPLATE = r'''
</html>
'''
def _test(request, form_class):
passed = False
if request.POST:
@@ -80,8 +81,10 @@ def test_per_form_format(request):
help_text='asdasd',
error_messages=dict(invalid='TEST CUSTOM ERROR MESSAGE'),
output_format=(
u'%(image)s testPerFieldCustomFormatString '
u'%(hidden_field)s %(text_field)s'
u(
'%(image)s testPerFieldCustomFormatString '
'%(hidden_field)s %(text_field)s'
)
)
)
return _test(request, CaptchaTestFormatForm)

View File

@@ -3,7 +3,8 @@ try:
except ImportError:
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('captcha.views',
urlpatterns = patterns(
'captcha.views',
url(r'image/(?P<key>\w+)/$', 'captcha_image', name='captcha-image', kwargs={'scale': 1}),
url(r'image/(?P<key>\w+)@2/$', 'captcha_image', name='captcha-image-2x', kwargs={'scale': 2}),
url(r'audio/(?P<key>\w+)/$', 'captcha_audio', name='captcha-audio'),

View File

@@ -1,4 +1,4 @@
from captcha.conf import settings
from captcha.conf import settings
from captcha.helpers import captcha_image_url
from captcha.models import CaptchaStore
from django.http import HttpResponse, Http404
@@ -27,6 +27,15 @@ except ImportError:
from django.utils import simplejson as json
NON_DIGITS_RX = re.compile('[^\d]')
# Distance of the drawn text from the top of the captcha image
from_top = 4
def getsize(font, text):
if hasattr(font, 'getoffset'):
return [x + y for x, y in zip(font.getsize(text), font.getoffset(text))]
else:
return font.getsize(text)
def captcha_image(request, key, scale=1):
@@ -38,8 +47,11 @@ def captcha_image(request, key, scale=1):
else:
font = ImageFont.load(settings.CAPTCHA_FONT_PATH)
size = font.getsize(text)
size = (size[0] * 2, int(size[1] * 1.2))
size = getsize(font, text)
size = (size[0] * 2, int(size[1] * 1.4))
if settings.CAPTCHA_BACKGROUND_COLOR == "transparent":
image = Image.new('RGBA', size)
else:
image = Image.new('RGB', size, settings.CAPTCHA_BACKGROUND_COLOR)
try:
@@ -56,7 +68,7 @@ def captcha_image(request, key, scale=1):
charlist.append(char)
for char in charlist:
fgimage = Image.new('RGB', size, settings.CAPTCHA_FOREGROUND_COLOR)
charimage = Image.new('L', font.getsize(' %s ' % char), '#000000')
charimage = Image.new('L', getsize(font, ' %s ' % char), '#000000')
chardraw = ImageDraw.Draw(charimage)
chardraw.text((0, 0), ' %s ' % char, font=font, fill='#ffffff')
if settings.CAPTCHA_LETTER_ROTATION:
@@ -67,7 +79,7 @@ def captcha_image(request, key, scale=1):
charimage = charimage.crop(charimage.getbbox())
maskimage = Image.new('L', size)
maskimage.paste(charimage, (xpos, 4, xpos + charimage.size[0], 4 + charimage.size[1]))
maskimage.paste(charimage, (xpos, from_top, xpos + charimage.size[0], from_top + charimage.size[1]))
size = maskimage.size
image = Image.composite(fgimage, image, maskimage)
xpos = xpos + 2 + charimage.size[0]