Created
August 21, 2019 20:21
-
-
Save fzembow/eda54ca61dc49e2dabc3f56c6643d555 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Signed URL generation demo | |
# Author: Fil Zembowicz <[email protected]> | |
usage = "AWS_REGION=... AWS_BUCKET=... AWS_UPLOAD_FOLDER=... flask run" | |
import boto3 | |
import os | |
import uuid | |
from flask import Flask, request, abort, jsonify | |
app = Flask(__name__) | |
AWS_REGION = os.getenv("AWS_REGION") | |
AWS_BUCKET = os.getenv("AWS_BUCKET") | |
AWS_UPLOAD_FOLDER = os.getenv("AWS_UPLOAD_FOLDER") | |
if not AWS_REGION or not AWS_BUCKET or not AWS_UPLOAD_FOLDER: | |
raise (AssertionError(usage)) | |
if AWS_UPLOAD_FOLDER.startswith("/"): | |
raise AssertionError("AWS_UPLOAD_FOLDER should not have a leading slash") | |
MIN_SIZE_BYTES = 1 | |
MAX_SIZE_BYTES = 10_000_000 | |
@app.route("/presigned-post") | |
def presigned_post(): | |
# You can pass other args from the formsort answer set. | |
# When creating the signedUrl, just include them like https://example.com/get-signed-url?something={{some_answer}} | |
# Filename will automatically be added onto that. | |
filename = request.args.get("filename") | |
if not filename: | |
abort(400) | |
filename, ext = os.path.splitext(filename) | |
# Mime types are also verified on the frontend per configuration set within Formsort, | |
# but you should also do it on the backend. | |
allowed_upload_mime_types = {".jpg": "image/jpg"} | |
if ext not in allowed_upload_mime_types: | |
abort(400) | |
mime_type = allowed_upload_mime_types[ext] | |
filename = f"{uuid.uuid4()}{ext}" | |
location = f"{AWS_UPLOAD_FOLDER}/{filename}" | |
headers = { | |
"acl": "public-read", | |
"Content-Type": mime_type, | |
"Cache-Control": "max-age=31536000,public", | |
} | |
conditions = [ | |
{"acl": "public-read"}, | |
{"Content-Type": mime_type}, | |
{"Cache-Control": "max-age=31536000,public"}, | |
# File sizes are also frontend-verified, but you should also verify on the backend. | |
["content-length-range", MIN_SIZE_BYTES, MAX_SIZE_BYTES], | |
{"key": location}, | |
] | |
s3 = boto3.client("s3", region_name=AWS_REGION) | |
post = s3.generate_presigned_post( | |
Bucket=AWS_BUCKET, Key=location, Conditions=conditions, Fields=headers | |
) | |
# You must return these three keys since they are required to actually upload the content. | |
# If you specify an answerValue in the response, that will be saved in the Formsort answer set. | |
# Otherwise, the full url (url + key) will be saved. This way, if your bucket allows GET, you can view | |
# the image immediately after. | |
response = jsonify({"url": post["url"], "headers": headers, "key": location}) | |
# This is just for the demo. In practice you will want to restrict to *.yourdomain.com and *.formsort.com | |
response.headers.add("Access-Control-Allow-Origin", "*") | |
return response | |
if __name__ == "__main__": | |
app.run(debug=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment