Skip to content

Commit 3cd64ad

Browse files
committed
update .gitignore
1 parent 7fd856f commit 3cd64ad

File tree

6 files changed

+198
-10
lines changed

6 files changed

+198
-10
lines changed

.gitignore

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,58 @@
1-
log/
2-
Uploads/
3-
build/
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*.pyo
5+
*.pyd
46
*.egg-info/
57
*.egg
6-
*.log
8+
*.env/
9+
*.venv/
10+
venv/
11+
.env
12+
.Python
13+
pip-log.txt
14+
pip-delete-this-directory.txt
15+
16+
# Java
717
target/
8-
!**/.mvn/** */
9-
!**/src/main/**/target/
10-
!**/src/test/**/target/
11-
!**/target/** */
18+
*.class
19+
*.jar
20+
*.war
21+
*.ear
22+
*.iml
23+
.gradle/
24+
.mvn/
25+
.mvn/wrapper/
26+
27+
# Logs and temp files
28+
*.log
29+
*.tmp
30+
*.swp
31+
*.swo
1232

13-
!**/src/main/**/build/
14-
!**/src/test/**/build/
33+
# OS-specific files
34+
.DS_Store
35+
Thumbs.db
36+
ehthumbs.db
37+
*.bak
1538

39+
# Editor and IDE files
1640
.vscode/
41+
.idea/
42+
*.sublime-workspace
43+
44+
# Flask, Django, and web framework cache
45+
instance/
46+
db.sqlite3
47+
*.sqlite3
48+
49+
# Compiled files
50+
*.out
51+
*.o
52+
*.so
53+
*.dll
54+
55+
# Ignore uploads and user-generated content
56+
uploads/
57+
media/
58+
staticfiles/

Unrestriced File Upload/python/build/lib/unrestricted/__init__.py

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .src.pathmanipulation import(
2+
is_valid_name,
3+
is_valid_extension,
4+
valid_filename
5+
)

Unrestriced File Upload/python/build/lib/unrestricted/fileupload/src/__init__.py

Whitespace-only changes.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env python3
2+
3+
from flask import Flask, request, jsonify, render_template
4+
import os
5+
import tempfile
6+
from werkzeug.exceptions import RequestEntityTooLarge
7+
import logging
8+
from .pathmanipulation import is_valid_name, is_valid_extension, valid_filename, get_unique_filename, get_magic_number, is_valid_magic_number
9+
10+
app = Flask(__name__)
11+
TEMPDIR = tempfile.gettempdir()
12+
UPLOADDIR = os.path.join(TEMPDIR + "/uploads/")
13+
LOGDIR = os.path.join(TEMPDIR + "/logs/")
14+
15+
os.makedirs(UPLOADDIR, exist_ok=True)
16+
os.makedirs(LOGDIR, exist_ok=True)
17+
18+
app.config["UPLOAD_DIRECTORY"] = UPLOADDIR
19+
app.config["MAX_CONTENT_LENGTH"] = 5 * 1024 * 1024 # 5 MB
20+
loglocation = os.path.join(LOGDIR + "app.log")
21+
logging.basicConfig(
22+
level=logging.INFO,
23+
handlers= [
24+
logging.FileHandler(loglocation),
25+
logging.StreamHandler()
26+
]
27+
)
28+
29+
logger = logging.getLogger(__name__)
30+
31+
@app.route("/", methods=["GET"])
32+
def main():
33+
"""Render the index.html page."""
34+
return render_template("index.html")
35+
36+
@app.errorhandler(413)
37+
def request_entity_too_large(error):
38+
return jsonify({"error": "File size exceeds the limit"}), 413
39+
40+
@app.route("/upload_file", methods=["POST"])
41+
def upload_file():
42+
max_length = request.max_content_length
43+
"""Handles file upload with validation."""
44+
try:
45+
logger.info("upload_file() method started")
46+
47+
if "file" not in request.files:
48+
return jsonify({"error": "No file part"}), 400
49+
50+
file = request.files["file"]
51+
if file.filename == "":
52+
return jsonify({"error": "No selected file"}), 400
53+
54+
if request.content_length > max_length:
55+
return jsonify({"error": "File size exceeds the limit"}), 400
56+
57+
if (file is None or not is_valid_name(file.filename)):
58+
return jsonify({"error" : "Invalid Filename"}), 400
59+
60+
if (file is None or not is_valid_extension(file.filename)):
61+
return jsonify({"error" : "Invalid Extension"}), 400
62+
63+
if file and is_valid_name(file.filename) and is_valid_extension(file.filename):
64+
ext = valid_filename(file.filename).rsplit(".", 1)[1].lower()
65+
if (is_valid_magic_number(file, ext) or is_valid_magic_number(file, ext) or is_valid_magic_number(file, ext)):
66+
unique_filename = get_unique_filename(app.config["UPLOAD_DIRECTORY"], valid_filename(file.filename))
67+
safe_file_path = os.path.join(app.config["UPLOAD_DIRECTORY"], unique_filename)
68+
file.save(safe_file_path)
69+
logger.info(f"File '{unique_filename}' uploaded successfully at {safe_file_path}")
70+
return jsonify({"success": "File uploaded successfully"}), 200
71+
else:
72+
return jsonify({"error" : "Invalid File Type"}), 400
73+
else:
74+
return jsonify({"error": "Invalid file format"}), 400
75+
except RequestEntityTooLarge as e:
76+
logger.error(f"File upload error: {str(e)}")
77+
return jsonify({"error": "File size exceeds the limit"}), 413
78+
except Exception as e:
79+
logger.error(f"File upload error: {str(e)}")
80+
return jsonify({"error": "Internal server error"}), 500
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
3+
import re
4+
import os
5+
6+
# Define Magic Numbers for allowed file types
7+
MAGIC_NUMBERS = {
8+
"png" : bytes([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]),
9+
"jpg" : bytes([0xFF, 0xD8, 0xFF]),
10+
"pdf" : bytes([0x25, 0x50, 0x44, 0x46])
11+
}
12+
13+
FILENAME_REGEX_PATTERN = r"^[a-zA-Z0-9\-\_]+$"
14+
ALLOWED_EXTENSIONS = set(MAGIC_NUMBERS.keys()) # this example allows the text and pdf files
15+
MAX_READ_SIZE = max(len(m) for m in MAGIC_NUMBERS.values())
16+
17+
"""This function checks if the filename is valid and doesn't contain any dot character in the name."""
18+
def is_valid_name(filename: str) -> bool:
19+
name = filename.rsplit('.', 1)[0]
20+
regex_match = re.search(FILENAME_REGEX_PATTERN, name)
21+
return True if(regex_match != None) else False
22+
23+
"""This function checks for the valid file extensions."""
24+
def is_valid_extension(filename: str) -> bool:
25+
ext = filename.rsplit(".", 1)[1].lower()
26+
return True if (ext in ALLOWED_EXTENSIONS) else False
27+
28+
def valid_filename(filename: str) -> str:
29+
name, ext = filename.rsplit('.', 1)
30+
name = re.sub(r"\.", "", name)
31+
if "%" in name:
32+
name = re.sub(r"\%", "", name)
33+
if "%" in ext:
34+
ext = re.sub(r"\%", "", ext).lower()
35+
regex_match = re.search(FILENAME_REGEX_PATTERN, name)
36+
return f"{regex_match.group(0)}.{ext}" # returns the sanitized filename with the extension for upload
37+
38+
def get_unique_filename(directory: str, filename: str) -> str:
39+
name, ext = filename.rsplit(".", 1)
40+
unique_filename = f"{name}.{ext}"
41+
count = 1
42+
43+
while os.path.exists(os.path.join(directory, unique_filename)):
44+
unique_filename = f"{name}_{count}.{ext}"
45+
count += 1
46+
47+
return unique_filename
48+
49+
"""Reads the first few bytes of the file to determine its magic number."""
50+
def get_magic_number(file) -> str:
51+
file.seek(0) # Reset file pointer
52+
magic_number = file.read(MAX_READ_SIZE) # Read the first 8 bytes (maximum magic number length)
53+
file.seek(0) # Reset pointer again after reading
54+
return magic_number
55+
56+
"""Checks if the file's magic number matches the expected magic number."""
57+
def is_valid_magic_number(file, extension: str) -> bool:
58+
expected_magic = MAGIC_NUMBERS.get(extension)
59+
if expected_magic:
60+
return get_magic_number(file).startswith(expected_magic)
61+
return False

0 commit comments

Comments
 (0)