Skip to content
Permalink
Browse files

Warp the captcha.

Fixes CVE-2016-1000008.
  • Loading branch information...
ralphbean committed Jul 5, 2016
1 parent e41d707 commit f01228557798175d343855e5eec1a5f86f27e623
Showing with 67 additions and 0 deletions.
  1. +67 −0 bodhi/captcha.py
@@ -17,6 +17,7 @@

import base64
import cryptography.fernet
import math
import random
import six

@@ -73,8 +74,74 @@ def jpeg_generator(plainkey, settings):
random.randint(padding, (image_height - height - padding)))
draw.text(position, plainkey, font=font, fill=font_color)

# Make it crazy!
img = warp_image(img)

return img

def warp_image(image):
r = 10 # individually warp a bunch of 10x10 tiles.
mesh_x = (image.size[0] / r) + 2
mesh_y = (image.size[1] / r) + 2

# Set up some random values we'll use over and over...
amplitude = random.uniform(6, 10)
period = random.uniform(0.65, 0.74)
offset = (
random.uniform(0, math.pi * 2 / period),
random.uniform(0, math.pi * 2 / period),
)

def _sine(x, y, a=amplitude, p=period, o=offset):
""" Given a single point, warp it. """
return (
math.sin((y + o[0]) * p) * a + x,
math.sin((x + o[1]) * p) * a + y,
)

def _clamp(x, y):
""" Don't warp things outside the bounds of the image. """
return (
max(0, min(image.size[0] - 1, x)),
max(0, min(image.size[1] - 1, y)),
)

# Build a map of the corners of our r by r tiles, warping each one.
warp = [
[
_clamp(*_sine(i * r, j * r))
for j in range(mesh_y)
] for i in range(mesh_x)
]

def _destination_rectangle(i, j):
""" Return a happy tile from the original space. """
return (i * r, j * r, (i + 1) * r, (j + 1) * r)

def _source_quadrilateral(i, j):
""" Return the set of warped corners for a given tile.
Specified counter-clockwise as a tuple.
"""
return (
warp[i ][j ][0], warp[i ][j ][1],
warp[i ][j+1][0], warp[i ][j+1][1],
warp[i+1][j+1][0], warp[i+1][j+1][1],
warp[i+1][j ][0], warp[i+1][j ][1],
)

# Finally, prepare our list of sources->destinations for PIL.
mesh = [
(
_destination_rectangle(i, j),
_source_quadrilateral(i, j),
)
for j in range(mesh_y-1)
for i in range(mesh_x-1)
]
# And do it.
return image.transform(image.size, Image.MESH, mesh, Image.BILINEAR)


def validate(request, cipherkey, value):
settings = request.registry.settings

0 comments on commit f012285

Please sign in to comment.
You can’t perform that action at this time.