[tor-commits] [bridgedb/master] Simplify Captcha and CaptchaProtectedResource keypair attributes.
isis at torproject.org
isis at torproject.org
Fri May 16 18:52:53 UTC 2014
commit f0b9885eabb832e6d0ba688c7723266e9f6b0117
Author: Isis Lovecruft <isis at torproject.org>
Date: Wed May 14 21:24:21 2014 +0000
Simplify Captcha and CaptchaProtectedResource keypair attributes.
All *Captcha and *CaptchaProtectedResource classes and subclasses (as
well as their interface specifications) now have `publicKey` and
`secretKey` attributes.
For the GimpCaptcha class, this involved switching the ordering of the
parameters for the initialisation method from:
GimpCaptcha(secretKey, publicKey, ...)
to:
GimpCaptcha(publicKey, secretKey, ...)
Make sure that the intialisations of all of these classes take the
public key *first*. YOU HAVE BEEN WARNED.
---
lib/bridgedb/HTTPServer.py | 103 ++++++++++++++--------------
lib/bridgedb/captcha.py | 125 ++++++++++++++++++++++++----------
lib/bridgedb/test/test_HTTPServer.py | 8 +--
lib/bridgedb/test/test_captcha.py | 54 +++++++--------
4 files changed, 172 insertions(+), 118 deletions(-)
diff --git a/lib/bridgedb/HTTPServer.py b/lib/bridgedb/HTTPServer.py
index 7598755..ead6d60 100644
--- a/lib/bridgedb/HTTPServer.py
+++ b/lib/bridgedb/HTTPServer.py
@@ -20,6 +20,8 @@ import textwrap
import time
import os
+from functools import partial
+
from ipaddr import IPv4Address
from ipaddr import IPv6Address
@@ -138,8 +140,11 @@ class CaptchaProtectedResource(resource.Resource):
isLeaf = True
- def __init__(self, useForwardedHeader=False, protectedResource=None):
+ def __init__(self, publicKey=None, secretKey=None,
+ useForwardedHeader=False, protectedResource=None):
resource.Resource.__init__(self)
+ self.publicKey = publicKey
+ self.secretKey = secretKey
self.useForwardedHeader = useForwardedHeader
self.resource = protectedResource
@@ -270,9 +275,7 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
.. _gimp-captcha: https://github.com/isislovecruft/gimp-captcha
"""
- def __init__(self, secretKey=None, publicKey=None, hmacKey=None,
- captchaDir='', useForwardedHeader=False,
- protectedResource=None):
+ def __init__(self, hmacKey=None, captchaDir='', **kwargs):
"""Protect a resource via this one, using a local CAPTCHA cache.
:param str secretkey: A PKCS#1 OAEP-padded, private RSA key, used for
@@ -294,10 +297,7 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
:param protectedResource: The resource to serve if the client
successfully passes the CAPTCHA challenge.
"""
- CaptchaProtectedResource.__init__(self, useForwardedHeader,
- protectedResource)
- self.secretKey = secretKey
- self.publicKey = publicKey
+ CaptchaProtectedResource.__init__(self, **kwargs)
self.hmacKey = hmacKey
self.captchaDir = captchaDir
@@ -340,7 +340,7 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
# Create a new HMAC key, specific to requests from this client:
clientIP = self.getClientIP(request)
clientHMACKey = crypto.getHMAC(self.hmacKey, clientIP)
- capt = captcha.GimpCaptcha(self.secretKey, self.publicKey,
+ capt = captcha.GimpCaptcha(self.publicKey, self.secretKey,
clientHMACKey, self.captchaDir)
try:
capt.get()
@@ -391,13 +391,9 @@ class ReCaptchaProtectedResource(CaptchaProtectedResource):
.. _reCaptcha: http://www.google.com/recaptcha
"""
- def __init__(self, recaptchaPrivKey='', recaptchaPubKey='', remoteip='',
- useForwardedHeader=False, protectedResource=None):
- CaptchaProtectedResource.__init__(self, useForwardedHeader,
- protectedResource)
- self.recaptchaPrivKey = recaptchaPrivKey
- self.recaptchaPubKey = recaptchaPubKey
- self.recaptchaRemoteIP = remoteip
+ def __init__(self, remoteIP=None, **kwargs):
+ CaptchaProtectedResource.__init__(self, **kwargs)
+ self.remoteIP = remoteIP
def _renderDeferred(self, checkedRequest):
"""Render this resource asynchronously.
@@ -442,7 +438,7 @@ class ReCaptchaProtectedResource(CaptchaProtectedResource):
- ``image`` is a string holding a binary, JPEG-encoded image.
- ``challenge`` is a unique string associated with the request.
"""
- capt = captcha.ReCaptcha(self.recaptchaPubKey, self.recaptchaPrivKey)
+ capt = captcha.ReCaptcha(self.publicKey, self.secretKey)
try:
capt.get()
@@ -464,8 +460,8 @@ class ReCaptchaProtectedResource(CaptchaProtectedResource):
:rtype: str
:returns: A fake IP address to report to the reCaptcha API server.
"""
- if self.recaptchaRemoteIP:
- remoteIP = self.recaptchaRemoteIP
+ if self.remoteIP:
+ remoteIP = self.remoteIP
else:
# generate a random IP for the captcha submission
remoteIP = IPv4Address(random.randint(0, 2**32-1)).compressed
@@ -520,7 +516,7 @@ class ReCaptchaProtectedResource(CaptchaProtectedResource):
% (clientIP, solution.error_code))
return (False, request)
- d = txrecaptcha.submit(challenge, response, self.recaptchaPrivKey,
+ d = txrecaptcha.submit(challenge, response, self.secretKey,
remoteIP).addCallback(checkResponse, request)
return d
@@ -862,6 +858,13 @@ def addWebServer(cfg, dist, sched):
:rtype: :api:`twisted.web.server.Site`
:returns: A webserver.
"""
+ captcha = None
+ fwdHeaders = cfg.HTTP_USE_IP_FROM_FORWARDED_HEADER
+ numBridges = cfg.HTTPS_N_BRIDGES_PER_ANSWER
+ fprInclude = cfg.HTTPS_INCLUDE_FINGERPRINTS
+
+ logging.info("Starting web servers...")
+
httpdist = resource.Resource()
httpdist.putChild('', WebRoot())
httpdist.putChild('robots.txt',
@@ -873,58 +876,56 @@ def addWebServer(cfg, dist, sched):
httpdist.putChild('options', WebResourceOptions())
httpdist.putChild('howto', WebResourceHowto())
- bridgesResource = WebResourceBridges(
- dist, sched, cfg.HTTPS_N_BRIDGES_PER_ANSWER,
- cfg.HTTP_USE_IP_FROM_FORWARDED_HEADER,
- includeFingerprints=cfg.HTTPS_INCLUDE_FINGERPRINTS)
-
if cfg.RECAPTCHA_ENABLED:
- protected = ReCaptchaProtectedResource(
- recaptchaPrivKey=cfg.RECAPTCHA_SEC_KEY,
- recaptchaPubKey=cfg.RECAPTCHA_PUB_KEY,
- remoteip=cfg.RECAPTCHA_REMOTEIP,
- useForwardedHeader=cfg.HTTP_USE_IP_FROM_FORWARDED_HEADER,
- protectedResource=bridgesResource)
- httpdist.putChild('bridges', protected)
-
+ publicKey = cfg.RECAPTCHA_PUB_KEY
+ secretKey = cfg.RECAPTCHA_SEC_KEY
+ captcha = partial(ReCaptchaProtectedResource,
+ remoteIP=cfg.RECAPTCHA_REMOTEIP)
elif cfg.GIMP_CAPTCHA_ENABLED:
- # Get the HMAC secret key for CAPTCHA challenges and create a new key
- # from it for use on the server:
+ # Get the master HMAC secret key for CAPTCHA challenges, and then
+ # create a new HMAC key from it for use on the server.
captchaKey = crypto.getKey(cfg.GIMP_CAPTCHA_HMAC_KEYFILE)
hmacKey = crypto.getHMAC(captchaKey, "Captcha-Key")
-
# Load or create our encryption keys:
secretKey, publicKey = crypto.getRSAKey(cfg.GIMP_CAPTCHA_RSA_KEYFILE)
-
- protected = GimpCaptchaProtectedResource(
- secretKey=secretKey,
- publicKey=publicKey,
- hmacKey=hmacKey,
- captchaDir=cfg.GIMP_CAPTCHA_DIR,
- useForwardedHeader=cfg.HTTP_USE_IP_FROM_FORWARDED_HEADER,
- protectedResource=bridgesResource)
+ captcha = partial(GimpCaptchaProtectedResource,
+ hmacKey=hmacKey,
+ captchaDir=cfg.GIMP_CAPTCHA_DIR)
+
+ bridges = WebResourceBridges(dist, sched, numBridges,
+ fwdHeaders, includeFingerprints=fprInclude)
+ if captcha:
+ # Protect the 'bridges' page with a CAPTCHA, if configured to do so:
+ protected = captcha(publicKey=publicKey,
+ secretKey=secretKey,
+ useForwardedHeader=fwdHeaders,
+ protectedResource=bridges)
httpdist.putChild('bridges', protected)
+ logging.info("Protecting resources with %s." % captcha.func.__name__)
else:
- httpdist.putChild('bridges', bridgesResource)
+ httpdist.putChild('bridges', bridges)
site = server.Site(httpdist)
if cfg.HTTP_UNENCRYPTED_PORT:
ip = cfg.HTTP_UNENCRYPTED_BIND_IP or ""
+ port = cfg.HTTP_UNENCRYPTED_PORT or 80
try:
- reactor.listenTCP(cfg.HTTP_UNENCRYPTED_PORT, site, interface=ip)
+ reactor.listenTCP(port, site, interface=ip)
except CannotListenError as error:
raise SystemExit(error)
+ logging.info("Started HTTP server on %s:%d" % (str(ip), int(port)))
if cfg.HTTPS_PORT:
- from twisted.internet.ssl import DefaultOpenSSLContextFactory
- #from OpenSSL.SSL import SSLv3_METHOD
ip = cfg.HTTPS_BIND_IP or ""
- factory = DefaultOpenSSLContextFactory(cfg.HTTPS_KEY_FILE,
- cfg.HTTPS_CERT_FILE)
+ port = cfg.HTTPS_PORT or 443
try:
- reactor.listenSSL(cfg.HTTPS_PORT, site, factory, interface=ip)
+ from twisted.internet.ssl import DefaultOpenSSLContextFactory
+ factory = DefaultOpenSSLContextFactory(cfg.HTTPS_KEY_FILE,
+ cfg.HTTPS_CERT_FILE)
+ reactor.listenSSL(port, site, factory, interface=ip)
except CannotListenError as error:
raise SystemExit(error)
+ logging.info("Started HTTPS server on %s:%d" % (str(ip), int(port)))
return site
diff --git a/lib/bridgedb/captcha.py b/lib/bridgedb/captcha.py
index ca2575c..e10bc81 100644
--- a/lib/bridgedb/captcha.py
+++ b/lib/bridgedb/captcha.py
@@ -124,22 +124,28 @@ class Captcha(object):
class ReCaptcha(Captcha):
- """A reCaptcha CAPTCHA.
+ """A CAPTCHA obtained from a remote reCaptcha_ API server.
:ivar str image: The CAPTCHA image.
:ivar str challenge: The ``'recaptcha_challenge_response'`` HTTP form
- field to pass to the client along with the CAPTCHA image.
+ field to pass to the client, along with the CAPTCHA image. See
+ :doc:`BridgeDB's captcha.html <templates/captcha.html>` Mako_ template
+ for an example usage.
+ :ivar str publicKey: The public reCaptcha API key.
+ :ivar str secretKey: The private reCaptcha API key.
+
+ .. _reCaptcha: https://code.google.com/p/recaptcha/
+ .. _Mako: http://docs.makotemplates.org/en/latest/syntax.html#page
"""
- def __init__(self, pubkey=None, privkey=None):
+ def __init__(self, publicKey=None, secretKey=None):
"""Create a new ReCaptcha CAPTCHA.
- :param str pubkey: The public reCaptcha API key.
- :param str privkey: The private reCaptcha API key.
+ :param str publicKey: The public reCaptcha API key.
+ :param str secretKey: The private reCaptcha API key.
"""
- super(ReCaptcha, self).__init__()
- self.pubkey = pubkey
- self.privkey = privkey
+ super(ReCaptcha, self).__init__(publicKey=publicKey,
+ secretKey=secretKey)
def get(self):
"""Retrieve a CAPTCHA from the reCaptcha API server.
@@ -154,11 +160,11 @@ class ReCaptcha(Captcha):
:ivar:`secretKey` are missing.
:raises HTTPError: If the server returned any HTTP error status code.
"""
- if not self.pubkey or not self.privkey:
+ if not self.publicKey or not self.secretKey:
raise CaptchaKeyError('You must supply recaptcha API keys')
urlbase = API_SSL_SERVER
- form = "/noscript?k=%s" % self.pubkey
+ form = "/noscript?k=%s" % self.publicKey
# Extract and store image from recaptcha
html = urllib2.urlopen(urlbase + form).read()
@@ -172,27 +178,45 @@ class ReCaptcha(Captcha):
class GimpCaptcha(Captcha):
- """A cached CAPTCHA image which was created with Gimp."""
+ """A locally cached CAPTCHA image which was created with gimp-captcha_.
+
+ :ivar str secretKey: A PKCS#1 OAEP-padded, private RSA key, used for
+ verifying the client's solution to the CAPTCHA.
+ :ivar str publickey: A PKCS#1 OAEP-padded, public RSA key. This is used to
+ hide the correct CAPTCHA solution within the
+ ``captcha_challenge_field`` HTML form field. That form field is given
+ to the a client along with the :ivar:`image` during the initial
+ CAPTCHA request, and the client *should* give it back to us later
+ during the CAPTCHA solution verification step.
+ :ivar bytes hmacKey: A client-specific HMAC secret key.
+ :ivar str cacheDir: The local directory which pre-generated CAPTCHA images
+ have been stored in. This can be set via the ``GIMP_CAPTCHA_DIR``
+ setting in the config file.
+ :type sched: :class:`bridgedb.schedule.ScheduledInterval`
+ :ivar sched: An time interval. After this much time has passed, the
+ CAPTCHA is considered stale, and all solutions are considered invalid
+ regardless of their correctness.
+
+ .. _gimp-captcha: https://github.com/isislovecruft/gimp-captcha
+ """
- def __init__(self, secretKey=None, publicKey=None, hmacKey=None,
+ def __init__(self, publicKey=None, secretKey=None, hmacKey=None,
cacheDir=None):
"""Create a ``GimpCaptcha`` which retrieves images from **cacheDir**.
- :param str secretkey: A PKCS#1 OAEP-padded, private RSA key, used for
- verifying the client's solution to the CAPTCHA.
:param str publickey: A PKCS#1 OAEP-padded, public RSA key, used for
creating the ``captcha_challenge_field`` string to give to a
client.
+ :param str secretKey: A PKCS#1 OAEP-padded, private RSA key, used for
+ verifying the client's solution to the CAPTCHA.
:param bytes hmacKey: A client-specific HMAC secret key.
:param str cacheDir: The local directory which pre-generated CAPTCHA
images have been stored in. This can be set via the
``GIMP_CAPTCHA_DIR`` setting in the config file.
- :raises GimpCaptchaError: if **cacheDir** is not a directory.
- :raises CaptchaKeyError: if any of **secretKey**, **publicKey**,
- or **hmacKey** is invalid, or missing.
+ :raises GimpCaptchaError: if :ivar:`cacheDir` is not a directory.
+ :raises CaptchaKeyError: if any of :ivar:`secretKey`,
+ :ivar:`publicKey`, or :ivar:`hmacKey` are invalid or missing.
"""
- super(GimpCaptcha, self).__init__()
-
if not cacheDir or not os.path.isdir(cacheDir):
raise GimpCaptchaError("Gimp captcha cache isn't a directory: %r"
% cacheDir)
@@ -201,10 +225,10 @@ class GimpCaptcha(Captcha):
"Invalid key supplied to GimpCaptcha: SK=%r PK=%r HMAC=%r"
% (secretKey, publicKey, hmacKey))
- self.secretKey = secretKey
- self.publicKey = publicKey
- self.cacheDir = cacheDir
+ super(GimpCaptcha, self).__init__(publicKey=publicKey,
+ secretKey=secretKey)
self.hmacKey = hmacKey
+ self.cacheDir = cacheDir
self.answer = None
@classmethod
@@ -215,7 +239,7 @@ class GimpCaptcha(Captcha):
``'captcha_challenge_field'`` HTTP form field.
:param str solution: The client's proposed solution to the CAPTCHA
that they were presented with.
- :param str secretkey: A PKCS#1 OAEP-padded, private RSA key, used for
+ :param str secretKey: A PKCS#1 OAEP-padded, private RSA key, used for
verifying the client's solution to the CAPTCHA.
:param bytes hmacKey: A private key for generating HMACs.
:rtype: bool
@@ -248,22 +272,51 @@ class GimpCaptcha(Captcha):
return False
def createChallenge(self, answer):
- """Encrypt the CAPTCHA **answer** and HMAC the encrypted data.
-
- Take a string containing the answer to a CAPTCHA and encrypts it to
- :attr:`publicKey`. The resulting encrypted blob is then HMACed with a
- client-specific :attr:`hmacKey`. These two strings are then joined
- together in the form:
-
- HMAC ";" ENCRYPTED_ANSWER
-
- where the HMAC MUST be the first 20 bytes. Lastly base64-encoded (in a
- URL safe manner).
+ """Encrypt-then-HMAC the CAPTCHA **answer**.
+
+ A challenge string consists of a URL-safe, base64-encoded string which
+ contains an ``HMAC`` concatenated with an ``ENC_BLOB``, in the
+ following form::
+
+ CHALLENGE := B64( HMAC | ENC_BLOB )
+ ENC_BLOB := RSA_ENC( ANSWER_BLOB )
+ ANSWER_BLOB := ( TIMESTAMP | ANSWER )
+
+ where
+ * ``B64`` is a URL-safe base64-encode function,
+ * ``RSA_ENC`` is the PKCS#1 RSA-OAEP encryption function,
+ * and the remaining feilds are specified as follows:
+
+ +-------------+--------------------------------------------+----------+
+ | Field | Description | Length |
+ +=============+============================================+==========+
+ | HMAC | An HMAC of the ``ENC_BLOB``, created with | 20 bytes |
+ | | the client-specific :ivar:`hmacKey`, by | |
+ | | applying :func:`~crypto.getHMAC` to the | |
+ | | ``ENC_BLOB``. | |
+ +-------------+--------------------------------------------+----------+
+ | ENC_BLOB | An encrypted ``ANSWER``, created with | varies |
+ | | a PKCS#1 OAEP-padded RSA :ivar:`publicKey`.| |
+ +-------------+--------------------------------------------+----------+
+ | ANSWER | A string containing answer to this | 8 bytes |
+ | | CAPTCHA :ivar:`image`. | |
+ +-------------+--------------------------------------------+----------+
+
+ The steps taken to produce a ``CHALLENGE`` are then:
+
+ 1. Encrypt the ``ANSWER`` to :ivar:`publicKey` to create
+ the ``ENC_BLOB``.
+
+ 2. Use the client-specific :ivar:`hmacKey` to apply the
+ :func:`~crypto.getHMAC` function to the ``ENC_BLOB``, obtaining
+ an ``HMAC``.
+
+ 3. Create the final ``CHALLENGE`` string by concatenating the
+ ``HMAC`` and ``ENC_BLOB``, then base64-encoding the result.
:param str answer: The answer to a CAPTCHA.
:rtype: str
- :returns: An HMAC of, as well as a string containing the URL-safe,
- base64-encoded encrypted **answer**.
+ :returns: A challenge string.
"""
encrypted = self.publicKey.encrypt(answer)
hmac = crypto.getHMAC(self.hmacKey, encrypted)
diff --git a/lib/bridgedb/test/test_HTTPServer.py b/lib/bridgedb/test/test_HTTPServer.py
index 570fe9c..8bc1da7 100644
--- a/lib/bridgedb/test/test_HTTPServer.py
+++ b/lib/bridgedb/test/test_HTTPServer.py
@@ -274,9 +274,9 @@ class ReCaptchaProtectedResourceTests(unittest.TestCase):
# (None, None) is the (distributor, scheduleInterval):
self.protectedResource = HTTPServer.WebResourceBridges(None, None)
self.captchaResource = HTTPServer.ReCaptchaProtectedResource(
- recaptchaPrivKey='42',
- recaptchaPubKey='23',
- remoteip='111.111.111.111',
+ publicKey='23',
+ secretKey='42',
+ remoteIP='111.111.111.111',
useForwardedHeader=True,
protectedResource=self.protectedResource)
@@ -365,7 +365,7 @@ class ReCaptchaProtectedResourceTests(unittest.TestCase):
def test_getRemoteIP_useRandomIP(self):
"""Check that removing our remoteip setting produces a random IP."""
- self.captchaResource.recaptchaRemoteIP = None
+ self.captchaResource.remoteIP = None
ip = self.captchaResource.getRemoteIP()
realishIP = ipaddr.IPv4Address(ip).compressed
self.assertTrue(realishIP)
diff --git a/lib/bridgedb/test/test_captcha.py b/lib/bridgedb/test/test_captcha.py
index a383545..536f29e 100644
--- a/lib/bridgedb/test/test_captcha.py
+++ b/lib/bridgedb/test/test_captcha.py
@@ -50,8 +50,8 @@ class ReCaptchaTests(unittest.TestCase):
def test_init(self):
"""Check the ReCaptcha class stored the private and public keys."""
- self.assertEquals(self.c.privkey, 'sekrit')
- self.assertEquals(self.c.pubkey, 'publik')
+ self.assertEquals(self.c.secretKey, 'sekrit')
+ self.assertEquals(self.c.publicKey, 'publik')
def test_get(self):
"""Test get() method."""
@@ -109,32 +109,32 @@ class GimpCaptchaTests(unittest.TestCase):
a CaptchaKeyError.
"""
self.assertRaises(captcha.CaptchaKeyError, captcha.GimpCaptcha,
- None, self.publik, self.hmacKey, self.cacheDir)
+ self.publik, None, self.hmacKey, self.cacheDir)
def test_init_noPublicKey(self):
"""__init__() without publicKey should raise a CaptchaKeyError."""
self.assertRaises(captcha.CaptchaKeyError, captcha.GimpCaptcha,
- self.sekrit, None, self.hmacKey, self.cacheDir)
+ None, self.sekrit, self.hmacKey, self.cacheDir)
def test_init_noHMACKey(self):
"""__init__() without hmacKey should raise a CaptchaKeyError."""
self.assertRaises(captcha.CaptchaKeyError, captcha.GimpCaptcha,
- self.sekrit, self.publik, None, self.cacheDir)
+ self.publik, self.sekrit, None, self.cacheDir)
def test_init_noCacheDir(self):
"""__init__() without cacheDir should raise a CaptchaKeyError."""
self.assertRaises(captcha.GimpCaptchaError, captcha.GimpCaptcha,
- self.sekrit, self.publik, self.hmacKey, None)
+ self.publik, self.sekrit, self.hmacKey, None)
def test_init_badCacheDir(self):
"""GimpCaptcha with bad cacheDir should raise GimpCaptchaError."""
self.assertRaises(captcha.GimpCaptchaError, captcha.GimpCaptcha,
- self.sekrit, self.publik, self.hmacKey,
+ self.publik, self.sekrit, self.hmacKey,
self.cacheDir.rstrip('chas'))
def test_init(self):
"""Test that __init__ correctly initialised all the values."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
self.assertIsNone(c.answer)
self.assertIsNone(c.image)
@@ -142,14 +142,14 @@ class GimpCaptchaTests(unittest.TestCase):
def test_createChallenge(self):
"""createChallenge() should return the encrypted CAPTCHA answer."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
challenge = c.createChallenge('w00t')
self.assertIsInstance(challenge, basestring)
def test_createChallenge_base64(self):
"""createChallenge() return value should be urlsafe base64-encoded."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
challenge = c.createChallenge('w00t')
decoded = urlsafe_b64decode(challenge)
@@ -157,7 +157,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_createChallenge_hmacValid(self):
"""The HMAC in createChallenge() return value should be valid."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
challenge = c.createChallenge('ShouldHaveAValidHMAC')
decoded = urlsafe_b64decode(challenge)
@@ -168,7 +168,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_createChallenge_decryptedAnswerMatches(self):
"""The HMAC in createChallenge() return value should be valid."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
answer = 'ThisAnswerShouldDecryptToThis'
challenge = c.createChallenge(answer)
@@ -182,7 +182,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_get(self):
"""GimpCaptcha.get() should return image and challenge strings."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
self.assertIsInstance(image, basestring)
@@ -191,7 +191,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_get_emptyCacheDir(self):
"""An empty cacheDir should raise GimpCaptchaError."""
os.makedirs(self.badCacheDir)
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.badCacheDir)
self.assertRaises(captcha.GimpCaptchaError, c.get)
shutil.rmtree(self.badCacheDir)
@@ -205,7 +205,7 @@ class GimpCaptchaTests(unittest.TestCase):
fh.flush()
os.chmod(badFile, 0266)
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.badCacheDir)
# This should hit the second `except:` clause in get():
self.assertRaises(captcha.GimpCaptchaError, c.get)
@@ -213,7 +213,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check(self):
"""A correct answer and valid challenge should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
self.assertEquals(
@@ -222,7 +222,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_blankAnswer(self):
"""A blank answer and valid challenge should return False."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
self.assertEquals(
@@ -231,7 +231,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_nonBase64(self):
"""Valid answer and challenge with invalid base64 returns False."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
challengeBadB64 = challenge.rstrip('==') + "\x42\x42\x42"
@@ -244,7 +244,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_caseInsensitive_lowercase(self):
"""A correct answer in lowercase characters should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
solution = c.answer.lower()
@@ -254,7 +254,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_caseInsensitive_uppercase(self):
"""A correct answer in uppercase characters should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
solution = c.answer.upper()
@@ -264,7 +264,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_encoding_utf8(self):
"""A correct answer in utf-8 lowercase should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
solution = c.answer.encode('utf8')
@@ -274,7 +274,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_encoding_ascii(self):
"""A correct answer in utf-8 lowercase should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
solution = c.answer.encode('ascii')
@@ -284,7 +284,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_encoding_unicode(self):
"""A correct answer in utf-8 lowercase should return True."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
solution = unicode(c.answer)
@@ -294,7 +294,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_missingHMACbytes(self):
"""A challenge that is missing part of the HMAC should return False."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
challengeBadHMAC = challenge[:10] + challenge[20:]
@@ -304,7 +304,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_missingAnswerbytes(self):
"""Partial encrypted answers in challenges should return False."""
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
challengeBadOrig = challenge[:20] + challenge[30:]
@@ -315,7 +315,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_badHMACkey(self):
"""A challenge with a bad HMAC key should return False."""
hmacKeyBad = crypto.getKey('test_gimpCaptcha_badHMACkey')
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
self.assertEquals(
@@ -325,7 +325,7 @@ class GimpCaptchaTests(unittest.TestCase):
def test_check_badRSAkey(self):
"""A challenge with a bad RSA secret key should return False."""
secretKeyBad, publicKeyBad = crypto.getRSAKey('test_gimpCaptcha_badRSAkey')
- c = captcha.GimpCaptcha(self.sekrit, self.publik, self.hmacKey,
+ c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey,
self.cacheDir)
image, challenge = c.get()
self.assertEquals(
More information about the tor-commits
mailing list