2010-02-09 22 views
16

Estoy escribiendo mi propio sistema de captcha para el registro de usuarios. Entonces, necesito crear una URL adecuada para recibir imágenes captcha generadas. Generación se ve así:Django urlsafe decodificación base64 con descifrado

_cipher = cipher.new(settings.CAPTCHA_SECRET_KEY, cipher.MODE_ECB) 
_encrypt_block = lambda block: _cipher.encrypt(block + ' ' * (_cipher.block_size - len(block) % _cipher.block_size)) 
#... 
a = (self.rightnum, self.animal_type[1]) 
serialized = pickle.dumps(a) 
encrypted = _encrypt_block(serialized) 
safe_url = urlsafe_b64encode(encrypted) 

Pero entonces yo estoy tratando de recibir esta tecla mediante petición GET en la función de vista, se produce un error en urlsafe_b64decode() con "asignación de caracteres debe devolver número entero, Ninguno o Unicode" error:

def captcha(request): 
    try: 
    key = request.REQUEST['key'] 
    decoded = urlsafe_b64decode(key) 
    decrypted = _decrypt_block(decoded) 
    deserialized = pickle.loads(decrypted) 
    return HttpResponse(deserialized) 
    except KeyError: 
    return HttpResponseBadRequest() 

me encontré con que en la salida del urlsafe_b64encode hay un str, pero solicitud GET devuelve un objeto unicode (sin embargo, se trata de una cadena de la derecha). Str() no ayudó (devuelve el error de decodificación en el interior de django), y si uso la clave. repr funciona, pero el descifrador no funciona con un error "Las cadenas de entrada deben ser múltiplos de 16". Dentro de un archivo de prueba, toda esta construcción funciona perfectamente, no puedo entender, ¿qué pasa?

+0

¿Es necesario el cifrado? ¿No podría la generación del captcha almacenar la respuesta correcta en el servidor de datos de sesión? ¿O estás tratando de evitar eso? – MattH

+0

Simplemente no lo pensé aún. Pero este problema es interesante y quiero entender por qué ocurre. – Enchantner

+0

'key = str (request.REQUEST ['key'])' no funciona? – MattH

Respuesta

32

El problema es que b64decode bastante explícitamente solo puede tomar bytes (una cadena), no unicode.

>>> import base64 
>>> test = "Hi, I'm a string" 
>>> enc = base64.urlsafe_b64encode(test) 
>>> enc 
'SGksIEknbSBhIHN0cmluZw==' 
>>> uenc = unicode(enc) 
>>> base64.urlsafe_b64decode(enc) 
"Hi, I'm a string" 
>>> base64.urlsafe_b64decode(uenc) 
Traceback (most recent call last): 
... 
TypeError: character mapping must return integer, None or unicode 

Puesto que usted sabe que sus datos sólo contiene datos ASCII (que es lo que base64encode volverá), debe ser seguro para codificar sus puntos de código Unicode como ASCII o UTF-8 bytes, los bytes serán equivalentes a la ASCII que esperabas

>>> base64.urlsafe_b64decode(uenc.encode("ascii")) 
"Hi, I'm a string" 
+2

Esto ayuda a resolver un problema relacionado que tengo en un servidor web python. – hughdbrown

+1

"usted sabe que sus datos solo contienen datos ASCII" - y es por eso que escribiría '.encode (" ascii ")'. –

+0

Sí, "ascii" sería mejor. Actualizado. –

3

¡Resolví el problema!

deserialized = pickle.loads(captcha_decrypt(urlsafe_b64decode(key.encode('ascii')))) 
return HttpResponse(str(deserialized)) 

Pero todavía no entiendo, por qué no funcionó la primera vez.

Cuestiones relacionadas