I am creating a captcha just for an exercise. The creation of the captcha images seem fine. But every time I try validating the captcha challenge entered by the user, the validation is done against the next captcha. I am stuck at how to go with this. Function for creating captcha images- captcha.py
import random
import Image
import ImageFont
import ImageDraw
import ImageFilter
import JpegImagePlugin
import PngImagePlugin
def gen_captcha(text, fnt, fnt_sz, file_name, fmt='JPEG'):
fgcolor = random.randint(0,0xff0000)
bgcolor = fgcolor ^ 0xffffff
font = ImageFont.truetype(fnt,fnt_sz)
dim = font.getsize(text)
im = Image.new('RGB', (dim[0]+5,dim[1]+5), bgcolor)
d = ImageDraw.Draw(im)
x, y = im.size
r = random.randint
for num in range(100):
d.rectangle((r(0,x),r(0,y),r(0,x),r(0,y)),fill=r(0,0xffff00))
d.text((3,3), text, font=font, fill=fgcolor)
im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
im.save(file_name)
signup function from views.py
@app.route('/signup', methods = ['GET', 'POST'])
def signup():
if g.user is not None and g.user.is_authenticated():
return redirect(url_for('index'))
words = open('app/corncob_caps.txt').readlines()
captcha_word = words[random.randint(1,len(words))]
captcha_filename = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(10)) + '.jpg'
captcha.gen_captcha(captcha_word.strip(), 'app/os.ttf', 25, 'app/static/' + captcha_filename + '')
form = SignUpForm(captcha_word)
if form.validate_on_submit() == False:
return render_template('signup.html', form = form, filename = captcha_filename)
else:
user = User(form.email.data, form.password.data)
db.session.add(user)
db.session.commit()
flash('You have successfully signed up.')
flash('You may login now.')
return redirect(url_for('login'))
return render_template('signup.html', form = form, filename = captcha_filename)
I am passing the captcha_word to my form class. The form class is:
class SignUpForm(Form):
email = EmailField('Email Address', validators = [email()])
password = PasswordField('Password', validators = [Required('Please enter a valid password between 8 and 30 characters.'), Length(min = 8, max = 30)])
captcha = TextField('Captcha', validators = [Required('You must enter the challenge captcha.')])
submit = SubmitField('Create Account')
captcha_word = ''
def __init__(self, word, *args, **kwargs):
Form.__init__(self, *args, **kwargs)
self.get_word(word)
def get_word(self, word):
self.captcha_word = word
def validate(self):
if not Form.validate(self):
return False
elif self.captcha_word != self.captcha.data.upper():
print self.captcha_word
print self.captcha.data.upper()
self.captcha.errors.append("Wrong captcha!")
return False
user = self.get_user()
if user:
self.email.errors.append("That email is already taken.")
return False
else:
return True
def get_user(self):
return User.query.filter_by(email = self.email.data.lower()).first()
I inserted the two print statements inside to see why the comparison was coming wrong. The first print showed the next captcha whereas the print self.captcha.data.upper()
displayed the user entered data.
I am not sure, but it seems the signup route is being called twice. But I don't know how to fix this. Any ideas?