Подтвердить что ты не робот

Django urlsafe base64 декодирование с расшифровкой

Я пишу свою собственную систему captcha для регистрации пользователя. Поэтому мне нужно создать подходящий URL для получения сгенерированных изображений captcha. Поколение выглядит следующим образом:

_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)

Но затем я пытаюсь получить этот ключ с помощью запроса GET в функции просмотра, он не работает на urlsafe_b64decode(), поскольку "сопоставление символов должно возвращать целое число, None или 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()

Я обнаружил, что на выходе urlsafe_b64encode есть str, но GET-запрос возвращает объект unicode (тем не менее это правильная строка). Str() не помогло (он возвращает ошибку декодирования глубоко внутри django), и если я использую ключ. repr, он работает, но дешифратор не работает с ошибкой "Строки ввода должны быть множественными из 16 в длину". Внутри тестового файла вся эта конструкция отлично работает, я не могу понять, что неправильно?

4b9b3361

Ответ 1

Проблема в том, что b64decode достаточно явно может принимать только байты (строки), а не 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

Поскольку вы знаете, что ваши данные содержат только данные ASCII (то, что будет возвращать base64encode), должно быть безопасно кодировать ваши кодовые точки юникода в виде байтов ASCII или UTF-8, эти байты будут эквивалентны ожидаемому ASCII.

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

Ответ 2

Я решил проблему!

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

Но все же я не понимаю, почему это не сработало в первый раз.