def test_createChallenge_base64(self): """createChallenge() return value should be urlsafe base64-encoded.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) challenge = c.createChallenge('w00t') decoded = urlsafe_b64decode(challenge) self.assertTrue(decoded)
def test_check(self): """A correct answer and valid challenge should return True.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() self.assertEquals(c.check(challenge, c.answer, c.secretKey, c.hmacKey), True)
def getCaptchaImage(self, request): """Get a random CAPTCHA image from our **captchaDir**. Creates a :class:`~bridgedb.captcha.GimpCaptcha`, and calls its :meth:`~bridgedb.captcha.GimpCaptcha.get` method to return a random CAPTCHA and challenge string. :type request: :api:`twisted.web.http.Request` :param request: A client's initial request for some other resource which is protected by this one (i.e. protected by a CAPTCHA). :returns: A 2-tuple of ``(image, challenge)``, where:: - ``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) clientHMACKey = crypto.getHMAC(self.hmacKey, clientIP) capt = captcha.GimpCaptcha(self.publicKey, self.secretKey, clientHMACKey, self.captchaDir) try: capt.get() except captcha.GimpCaptchaError as error: logging.error(error) except Exception as error: # pragma: no cover logging.error("Unhandled error while retrieving Gimp captcha!") logging.exception(error) return (capt.image, capt.challenge)
def test_init(self): """Test that __init__ correctly initialised all the values.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) self.assertIsNone(c.answer) self.assertIsNone(c.image) self.assertIsNone(c.challenge)
def test_get_emptyCacheDir(self): """An empty cacheDir should raise GimpCaptchaError.""" os.makedirs(self.badCacheDir) c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.badCacheDir) self.assertRaises(captcha.GimpCaptchaError, c.get) shutil.rmtree(self.badCacheDir)
def test_check_blankAnswer(self): """A blank answer and valid challenge should return False.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() self.assertEquals(c.check(challenge, None, c.secretKey, c.hmacKey), False)
def test_get(self): """GimpCaptcha.get() should return image and challenge strings.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() self.assertIsInstance(image, basestring) self.assertIsInstance(challenge, basestring)
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.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() self.assertEquals( c.check(challenge, c.answer, c.secretKey, hmacKeyBad), False)
def test_check_missingAnswerbytes(self): """Partial encrypted answers in challenges should return False.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() challengeBadOrig = challenge[:20] + challenge[30:] self.assertEquals( c.check(challengeBadOrig, c.answer, c.secretKey, c.hmacKey), False)
def test_check_missingHMACbytes(self): """A challenge that is missing part of the HMAC should return False.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() challengeBadHMAC = challenge[:10] + challenge[20:] self.assertEquals( c.check(challengeBadHMAC, c.answer, c.secretKey, c.hmacKey), False)
def test_check_encoding_unicode(self): """A correct answer in utf-8 lowercase should return True.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() solution = unicode(c.answer) self.assertEquals(c.check(challenge, solution, c.secretKey, c.hmacKey), True)
def test_check_caseInsensitive_uppercase(self): """A correct answer in uppercase characters should return True.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() solution = c.answer.upper() self.assertEquals(c.check(challenge, solution, c.secretKey, c.hmacKey), True)
def test_check_nonBase64(self): """Valid answer and challenge with invalid base64 returns False.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) image, challenge = c.get() challengeBadB64 = challenge.rstrip('==') + "\x42\x42\x42" self.assertEquals(c.check(challenge, c.answer, c.secretKey, c.hmacKey), True) self.assertEquals( c.check(challengeBadB64, c.answer, c.secretKey, c.hmacKey), False)
def test_createChallenge_hmacValid(self): """The HMAC in createChallenge() return value should be valid.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) challenge = c.createChallenge('ShouldHaveAValidHMAC') decoded = urlsafe_b64decode(challenge) hmac = decoded[:20] orig = decoded[20:] correctHMAC = crypto.getHMAC(self.hmacKey, orig) self.assertEquals(hmac, correctHMAC)
def test_get_unreadableCaptchaFile(self): """An unreadable CAPTCHA file should raise GimpCaptchaError.""" os.makedirs(self.badCacheDir) badFile = os.path.join(self.badCacheDir, 'uNr34dA81e.jpg') with open(badFile, 'w') as fh: fh.write(' ') fh.flush() os.chmod(badFile, 0266) 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) shutil.rmtree(self.badCacheDir)
def test_createChallenge_decryptedAnswerMatches(self): """The HMAC in createChallenge() return value should be valid.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) challenge = c.createChallenge('ThisAnswerShouldDecryptToThis') decoded = urlsafe_b64decode(challenge) hmac = decoded[:20] orig = decoded[20:] correctHMAC = crypto.getHMAC(self.hmacKey, orig) self.assertEqual(hmac, correctHMAC) decrypted = self.sekrit.decrypt(orig) timestamp = int(decrypted[:12].lstrip('0')) # The timestamp should be within 30 seconds of right now. self.assertApproximates(timestamp, int(time.time()), 30) self.assertEqual('ThisAnswerShouldDecryptToThis', decrypted[12:])
def test_createChallenge(self): """createChallenge() should return the encrypted CAPTCHA answer.""" c = captcha.GimpCaptcha(self.publik, self.sekrit, self.hmacKey, self.cacheDir) challenge = c.createChallenge('w00t') self.assertIsInstance(challenge, basestring)