Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide temporary download url in Flask?

Currently, my index.html file contains

<a href="static/file.ext">Download</a>

I want to change this so that the download url is only valid for a certain time. For example, how would I change it to

<a href="get_file?file=file.ext&token=TEMPORARYTOKEN">Download</a>

In my Flask file, I could then have

@app.route('/get_file')
def get_file():
    filename = request.args.get('file')
    token = request.args.get('token')
    if token is valid: # what can be done here
        return send_from_directory('static', filename)

How can I generate and handle the token? Or am I approaching this completely wrong?

like image 353
null Avatar asked Sep 04 '15 05:09

null


People also ask

How do I generate a URL in Flask?

The url_for() function is used to build a URL to the specific function dynamically. The first argument is the name of the specified function, and then we can pass any number of keyword argument corresponding to the variable part of the URL.


2 Answers

The best way to do that is to use itsdangerous package. You can generate a URL that last whatever time you want. Furthermore you could encode secretly any information within the URL. The good thing about that is that NO need to deal or store timestamps into the database

To generate a URL that last for 30 mins and encode user id within the token

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

s = Serializer('WEBSITE_SECRET_KEY', 60*30) # 60 secs by 30 mins
token = s.dumps({'user_id': currentuser.id}).decode('utf-8') # encode user id 

Use the following to generate the URL you want

url_for('get_file', token=token)

To validate a URL

@app.route('/get_file/<token>')
def get_file(token):
    s = Serializer('WEBSITE_SECRET_KEY')
    try:
        user_id = s.loads(token)['user_id']
    except:
        return None
    user = User.query.get(user_id)

    if not user:
        flash('This is an invalid or expired URL, please generate a new one!', 'warning')
        return redirect(url_for('another_route'))

    return send_from_directory('static', filename, as_attachment=True)
like image 136
disooqi Avatar answered Nov 12 '22 19:11

disooqi


There are a couple ways you can do this.

  1. Generate a UUID for your token and store it in a db table along with the desired expiration datetime. Then when someone calls the URL with the token, you can just check it against the db for validity and expiration.

  2. If you don't want to use a db to store the tokens, you can use GPG to encrypt a string that contains the expiration datetime and use the resulting encrypted string as your token. This means your token will be a lot longer than a UUID, but you'd avoid having to use a db.

I recommend using UUID and a db table.

like image 41
Kelly Keller-Heikkila Avatar answered Nov 12 '22 20:11

Kelly Keller-Heikkila