59 lines
1.8 KiB
Python
59 lines
1.8 KiB
Python
import os
|
|
from typing import Optional
|
|
from werkzeug.utils import secure_filename
|
|
|
|
def clean_path(path: str, base_dir: Optional[str] = None) -> str:
|
|
"""
|
|
Clean and secure a file path, ensuring it's safe and within allowed directories.
|
|
|
|
Args:
|
|
path: The path to clean
|
|
base_dir: Optional base directory to ensure path stays within
|
|
|
|
Returns:
|
|
str: Cleaned and secured path
|
|
"""
|
|
# Remove any leading/trailing slashes and normalize path separators
|
|
path = path.strip('/\\')
|
|
path = os.path.normpath(path)
|
|
|
|
# If base_dir is provided, ensure path stays within it
|
|
if base_dir:
|
|
base_dir = os.path.normpath(base_dir)
|
|
# Get absolute paths
|
|
abs_path = os.path.abspath(path)
|
|
abs_base = os.path.abspath(base_dir)
|
|
|
|
# Check if path is within base directory
|
|
if not abs_path.startswith(abs_base):
|
|
raise ValueError("Path is outside of allowed directory")
|
|
|
|
# Return path relative to base directory
|
|
return os.path.relpath(abs_path, abs_base)
|
|
|
|
# If no base_dir, just return the cleaned path
|
|
return path
|
|
|
|
def secure_file_path(filename: str) -> str:
|
|
"""
|
|
Secure a filename using Werkzeug's secure_filename and add a timestamp.
|
|
|
|
Args:
|
|
filename: The original filename
|
|
|
|
Returns:
|
|
str: Secured filename with timestamp
|
|
"""
|
|
from datetime import datetime
|
|
|
|
# Get file extension
|
|
_, ext = os.path.splitext(filename)
|
|
|
|
# Secure the base filename
|
|
secure_name = secure_filename(filename)
|
|
|
|
# Add timestamp to prevent filename collisions
|
|
timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
|
|
|
|
# Combine parts
|
|
return f"{os.path.splitext(secure_name)[0]}_{timestamp}{ext}" |