[tor-commits] [bridgedb/master] Rewrite GimpCaptchaProtectedResource to use RSA & HMAC keys for verification.
isis at torproject.org
isis at torproject.org
Sun Mar 16 19:04:58 UTC 2014
commit c9496cd45c295e292b5966ad022e2c305f2dbe37
Author: Isis Lovecruft <isis at torproject.org>
Date: Wed Mar 12 00:03:18 2014 +0000
Rewrite GimpCaptchaProtectedResource to use RSA & HMAC keys for verification.
---
lib/bridgedb/HTTPServer.py | 56 ++++++++++++++++++++++++++++++++++----------
1 file changed, 43 insertions(+), 13 deletions(-)
diff --git a/lib/bridgedb/HTTPServer.py b/lib/bridgedb/HTTPServer.py
index 4deac25..ff9c7f3 100644
--- a/lib/bridgedb/HTTPServer.py
+++ b/lib/bridgedb/HTTPServer.py
@@ -115,9 +115,10 @@ def replaceErrorPage(error, template_name=None):
class CaptchaProtectedResource(twisted.web.resource.Resource):
"""A general resource protected by some form of CAPTCHA."""
+ isLeaf = True
+
def __init__(self, useForwardedHeader=False, resource=None):
twisted.web.resource.Resource.__init__(self)
- self.isLeaf = resource.isLeaf
self.useForwardedHeader = useForwardedHeader
self.resource = resource
@@ -234,9 +235,33 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
.. _gimp-captcha: https://github.com/isislovecruft/gimp-captcha
"""
- def __init__(self, captchaDir='',
- useForwardedHeader=False, resource=None):
+ def __init__(self, secretKey=None, publicKey=None, hmacKey=None,
+ captchaDir='', useForwardedHeader=False, resource=None):
+ """Protect a **resource** via this one, using a local CAPTCHA cache.
+
+ :param str secretkey: A PKCS#1 OAEP-padded, private RSA key, used for
+ verifying the client's solution to the CAPTCHA. See
+ :func:`bridgedb.crypto.getRSAKey` and the
+ ``GIMP_CAPTCHA_RSA_KEYFILE`` config setting.
+ :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 bytes hmacKey: The master HMAC key, used for validating CAPTCHA
+ challenge strings in :meth:`captcha.GimpCaptcha.check`. The file
+ where this key is stored can be set via the
+ ``GIMP_CAPTCHA_HMAC_KEYFILE`` option in the config file.
+ :param str captchaDir: The directory where the cached CAPTCHA images
+ are stored. See the ``GIMP_CAPTCHA_DIR`` config setting.
+ :param bool useForwardedHeader: If ``True``, obtain the client's IP
+ address from the ``X-Forwarded-For`` HTTP header.
+ :type resource: :api:`twisted.web.resource.Resource`
+ :param resource: The resource to serve if the client successfully
+ passes the CAPTCHA challenge.
+ """
CaptchaProtectedResource.__init__(self, useForwardedHeader, resource)
+ self.secretKey = secretKey
+ self.publicKey = publicKey
+ self.hmacKey = hmacKey
self.captchaDir = captchaDir
def checkSolution(self, request):
@@ -255,12 +280,15 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
:rtupe: bool
:returns: True, if the CAPTCHA solution was valid; False otherwise.
"""
- challenge, response = self.extractClientSolution(request)
+ challenge, solution = self.extractClientSolution(request)
clientIP = self.getClientIP(request)
- solution = captcha.GimpCaptcha.check(challenge, response, clientIP)
- logging.debug("Captcha from %r. Parameters: %r"
- % (Util.logSafely(clientIP), request.args))
- return solution
+ clientHMACKey = crypto.getHMAC(self.hmacKey, clientIP)
+ valid = captcha.GimpCaptcha.check(challenge, solution,
+ self.secretKey, clientHMACKey)
+ logging.debug("%sorrect captcha from %r: %r." % (
+ "C" if valid else "Inc", Util.logSafely(clientIP), solution))
+
+ return valid
def getCaptchaImage(self, request):
"""Get a random CAPTCHA image from our **captchaDir**.
@@ -276,18 +304,20 @@ class GimpCaptchaProtectedResource(CaptchaProtectedResource):
- ``image`` is a string holding a binary, JPEG-encoded image.
- ``challenge`` is a unique string associated with the request.
"""
+ # Create a new HMAC key, specific to requests from this client:
clientIP = self.getClientIP(request)
- c = captcha.GimpCaptcha(self.captchaDir, clientIP)
-
+ clientHMACKey = crypto.getHMAC(self.hmacKey, clientIP)
+ capt = captcha.GimpCaptcha(self.secretKey, self.publicKey,
+ clientHMACKey, self.captchaDir)
try:
- c.get()
+ capt.get()
except captcha.GimpCaptchaError as error:
logging.error(error)
except Exception as error:
logging.error("Unhandled error while retrieving Gimp captcha!")
- logging.error(error)
+ logging.exception(error)
- return (c.image, c.challenge)
+ return (capt.image, capt.challenge)
def render_GET(self, request):
"""Get a random CAPTCHA from our local cache directory and serve it to
More information about the tor-commits
mailing list