We had a problem of getting a wallpaper from the user using Meilix Generator and use the wallpaper with the Meilix build scripts to generate the ISO. So, we were required to host the wallpaper on the server and downloaded by Travis CI during the build to include it in the ISO.
A solution is to render HTML templates and access data sent by POST using the request object from the flask. Redirect and url_for will be used to redirect the user once the upload is done and send_from_directory will help us to host the file under the /uploads that the user just uploaded which will be downloaded by the Travis for building the ISO.
We start by creating the HTML form marked with enctype=multipart/form-data.
<form action="upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"><br /><br /> <input type="submit" value="Upload"> </form>
First, we need imports of modules required. Most important is werkzeug.secure_filename().
import os from flask import Flask, render_template, request, redirect, url_for, send_from_directory from werkzeug import secure_file
Now, we’ll define where to upload and the type of file allowed for uploading. The path to upload directory on the server is defined by the extensions in app.config which is uploads/ here.
app.config['UPLOAD_FOLDER'] = 'uploads/' app.config['ALLOWED_EXTENSIONS'] = set(['png', 'jpg', 'jpeg'])
This functions will check for valid extension for the wallpaper which are png, jpg and jpeg in this case defined above in app.config.
def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']
After, getting the name of uploaded file from the user then using above function check if there are allowed file type and store it in a variable filename after that it move the files to the upload folder to save it.
Upload function check if the file name is safe and remove unsupported characters (line 3) after that moves it from a temporal folder to the upload folder. After moving, it renames the file as wallpaper so that the download link is same always which we have used in Meilix build script to download from server.
def upload(): file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) os.rename(UPLOAD_FOLDER + filename, UPLOAD_FOLDER+'wallpaper') filename = 'wallpaper'
At this point, we have only uploaded the wallpaper and renamed the uploaded file to ‘wallpaper’ only. We cannot access the file outside the server it will result in 403 error so to make it available, the uploaded file need to be registered and then hosted using below code snippet.
We can also register uploaded_file as build_only rule and use the SharedDataMiddleware.
@app.route('/uploads/<filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'],filename)
The hosted wallpaper is used by Meilix in Travis CI to generate ISO using the download link which remains same for the uploaded wallpaper.
Why should we use secure secure_filename() function?
just imagine someone sends the following information as the filename to your app.
filename = "../../../../home/username/.sh"
If the number of ../ is correct and you would join this with your UPLOAD_FOLDER the hacker might have the ability to modify a file on the server’s filesystem that he or she should not modify.
Now, let’s look how the function works.
secure_filename('../../../../home/username/.sh') 'home_username_.sh'
Improving the uploads
We can add validation to the size of the file to be uploaded so that in case a user tries to upload a file too much big that may increase load on the server.
from flask import Flask, Request app = Flask(__name__) app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024