devmrh
devmrh

Reputation: 1211

Generate temporary URLs in Django 2 Python 3

There is one same question in StackOverflow with this link: How to generate temporary URLs in Django

But the accepted answer code is for Python 2 and I converted it to Python 3:

import hashlib, zlib
import pickle as pickle
import urllib.request, urllib.parse, urllib.error

my_secret = "michnorts"

def encode_data(data):
    """Turn `data` into a hash and an encoded string, suitable for use with `decode_data`."""
    text = zlib.compress(pickle.dumps(data, 0)).encode('base64').replace('\n', '')
    m = hashlib.md5(my_secret + text).hexdigest()[:12]
    return m, text

def decode_data(hash, enc):
    """The inverse of `encode_data`."""
    text = urllib.parse.unquote(enc)
    m = hashlib.md5(my_secret + text).hexdigest()[:12]
    if m != hash:
        raise Exception("Bad hash!")
    data = pickle.loads(zlib.decompress(text.decode('base64')))
    return data

hash, enc = encode_data(['Hello', 'Goodbye'])
print(hash, enc)
print(decode_data(hash, enc))

But it have error :

    text = zlib.compress(pickle.dumps(data, 0)).encode('base64').replace('\n', '')
AttributeError: 'bytes' object has no attribute 'encode'

How should I fix this?

Upvotes: 1

Views: 972

Answers (2)

Dominique PERETTI
Dominique PERETTI

Reputation: 1083

I recommend to use the built-in secrets modules, especially secrets.token_urlsafe.

Upvotes: 0

Daniel Ruiz
Daniel Ruiz

Reputation: 620

Trying to adapt your code to Python 3, I came up with this:

import hashlib, zlib
import pickle as pickle
import urllib.request, urllib.parse, urllib.error
import base64

my_secret = "michnorts"

def encode_data(data):
    """Turn `data` into a hash and an encoded string, suitable for use with `decode_data`."""
    compressed_text = zlib.compress(pickle.dumps(data, 0))
    text = base64.b64encode(compressed_text).decode().replace('\n', '')
    m = hashlib.md5(str.encode('{}{}'.format(my_secret, text))).hexdigest()[:12]
    return m, text

def decode_data(hash, enc):
    """The inverse of `encode_data`."""
    text = urllib.parse.unquote(enc)
    m = hashlib.md5(str.encode('{}{}'.format(my_secret, text))).hexdigest()[:12]
    if m != hash:
        raise Exception("Bad hash!")
    data = pickle.loads(zlib.decompress(base64.b64decode(text)))
    return data

hash, enc = encode_data(['Hello', 'Goodbye'])
print(hash, enc)
print(decode_data(hash, enc))

There are some things that I needed to take into account:

  • in Python 3, the way to encode/decode into base64 is by using the base64 module
  • to cast a bytes object into a string, I used the bytes.decode method
  • to cast a string object into a bytes object, I used the str.encode function
  • the hashlib.md5 function accepts a bytesobject (strings need to be previously encoded)
  • I changed the way you concatenate strings (i.e. str1 + str2) with a more pythonic construction: '{}{}'.format(str1, str2)

I hope this will be helpful ;)

Upvotes: 4

Related Questions