-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathflask-example.py
More file actions
95 lines (71 loc) · 3.35 KB
/
flask-example.py
File metadata and controls
95 lines (71 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Flask example."""
import os
from http import HTTPStatus
from flask import Flask, request
from flask import jsonify
from werkzeug.utils import secure_filename
"""
Author: James Campbell
Date: Mon May 23 16:26:36 2016
Date Updated: 2 July 2019
What is this code: An example Flask connection
Why?: For me to remember later
"""
app = Flask(__name__)
ALLOWED_EXTENSIONS = ["zip", "gz", "bz2"]
def allowed_filename(filename: str) -> bool:
"""Define allowed file extensions."""
return "." in filename and filename.rsplit(".", 1)[1] in ALLOWED_EXTENSIONS
@app.route("/")
def hello_world():
"""Hello world example."""
return """\
<!DOCTYPE html><head><title>Flask test</title></head>\
<body style="font-family:monospace;">Hello, simply run\
<pre style="color:blue;">curl -X POST localhost:6969/upload\
-F file=@"assets/archive_name.tar.gz" -i</pre> to test from\
same folder you executed <pre style="color:blue;">python3\
flask-example.py</pre></body>
"""
@app.route("/upload", methods=["POST"])
def upload_csv() -> str:
"""Upload CSV example."""
if "file" not in request.files:
return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "No file provided"}), 400
submitted_file = request.files["file"]
if not submitted_file or not submitted_file.filename:
return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "No file selected"}), 400
if not allowed_filename(submitted_file.filename):
return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "File type not allowed"}), 400
filename = secure_filename(submitted_file.filename)
# Additional security check: ensure filename is not empty after sanitization
if not filename:
return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "Invalid filename"}), 400
basedir = os.path.abspath(os.path.dirname(__file__))
upload_folder = os.path.abspath(os.path.join(basedir, app.config["UPLOAD_FOLDER"]))
# Create directory with secure permissions if it doesn't exist
if not os.path.exists(upload_folder):
os.makedirs(upload_folder, mode=0o755, exist_ok=True)
# Construct full path and verify it's within the upload directory (prevent path traversal)
file_path = os.path.abspath(os.path.join(upload_folder, filename))
if not file_path.startswith(upload_folder):
return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "Invalid file path"}), 400
# Limit file size (optional but recommended)
# submitted_file.seek(0, os.SEEK_END)
# file_size = submitted_file.tell()
# submitted_file.seek(0)
# if file_size > MAX_FILE_SIZE:
# return jsonify({"status": HTTPStatus.BAD_REQUEST, "message": "File too large"}), 400
submitted_file.save(file_path)
out = {
"status": HTTPStatus.OK,
"filename": filename,
"message": f"{filename} saved successfully.",
}
return jsonify(out)
if __name__ == "__main__":
app.config["UPLOAD_FOLDER"] = "flaskme/"
# Debug mode disabled for security - use environment variable to enable in development
debug_mode = os.environ.get("FLASK_DEBUG", "False").lower() == "true"
app.run(port=6969, debug=debug_mode)
# curl -X POST localhost:6969/upload -F file=@"assets/archive_name.tar.gz" -i