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}"