import subprocess
import sys
import re
from pathlib import Path
from typing import Optional
def process_user_file_safe(filename: str) -> bool:
"""Secure file processing function with proper validation"""
try:
# Comprehensive input validation
if not is_valid_filename(filename):
print("Error: Invalid filename format")
return False
filepath = Path(filename)
# Security checks
if not filepath.exists():
print("Error: File not found")
return False
if not is_file_in_allowed_directory(filepath):
print("Error: File not in allowed directory")
return False
if not is_safe_file_type(filepath):
print("Error: File type not allowed")
return False
print(f"Processing file: {filename}")
# SECURE: Use subprocess with argument lists
backup_dir = Path("/backup")
backup_dir.mkdir(exist_ok=True)
backup_path = backup_dir / f"{filepath.name}.bak"
# Safe file copy using subprocess
result = subprocess.run(
['cp', str(filepath), str(backup_path)],
capture_output=True,
text=True,
timeout=30
)
if result.returncode != 0:
print(f"Error copying file: {result.stderr}")
return False
# Safe file size check
size_result = subprocess.run(
['du', '-h', str(filepath)],
capture_output=True,
text=True,
timeout=10
)
if size_result.returncode == 0:
print(f"File size: {size_result.stdout.strip()}")
print("File processed successfully")
return True
except subprocess.TimeoutExpired:
print("Error: Operation timeout")
return False
except Exception as e:
print(f"Error: {e}")
return False
def is_valid_filename(filename: str) -> bool:
"""Validate filename using strict allowlist"""
# Allowlist pattern: alphanumeric, dots, hyphens, underscores
pattern = r'^[a-zA-Z0-9._-]+$'
return (
1 <= len(filename) <= 255 and # Reasonable length
re.match(pattern, filename) and
'..' not in filename and # Prevent directory traversal
not filename.startswith('.') and # No hidden files
filename.count('.') <= 2 # Reasonable number of dots
)
def is_file_in_allowed_directory(filepath: Path) -> bool:
"""Check if file is in allowed directory"""
allowed_dirs = [
Path('/home/user/documents').resolve(),
Path('/tmp/uploads').resolve(),
Path('/var/uploads').resolve()
]
try:
resolved_path = filepath.resolve()
return any(
str(resolved_path).startswith(str(allowed_dir))
for allowed_dir in allowed_dirs
)
except (OSError, RuntimeError):
return False
def is_safe_file_type(filepath: Path) -> bool:
"""Check if file type is allowed"""
allowed_extensions = {'.txt', '.csv', '.json', '.xml', '.log'}
return filepath.suffix.lower() in allowed_extensions
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: script.py <filename>")
print("Allowed file types: .txt, .csv, .json, .xml, .log")
sys.exit(1)
user_filename = sys.argv[1]
success = process_user_file_safe(user_filename)
sys.exit(0 if success else 1)