#!/usr/bin/env python3 # Test script to verify input sanitization functions import sys import os # Add the project root to the path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Import the sanitization functions from time_tracker.py def sanitize_csv_text(text): """Sanitize text for safe CSV writing""" if not text: return "" text = str(text) # Remove dangerous characters that could cause CSV injection dangerous_chars = ['=', '+', '-', '@', '\t', '\r', '\n'] for char in dangerous_chars: text = text.replace(char, '') # Remove Excel formula triggers text = re.sub(r'^[+\-=@]', '', text) # Truncate to reasonable length text = text[:500] # Strip whitespace return text.strip() def sanitize_filename(filename): """Sanitize filename for safe file operations""" if not filename: return "default.csv" text = str(filename) # Remove path separators and dangerous characters text = re.sub(r'[<>:"/\\|?*]', '', text) text = re.sub(r'\.\.', '', text) # Remove directory traversal # Remove leading/trailing dots and spaces text = text.strip('. ') # Ensure filename is not empty if not text or text.startswith('.'): return "default.csv" # Ensure .csv extension if not text.lower().endswith('.csv'): text += '.csv' return text def sanitize_config_text(text, max_length=100): """Sanitize text for configuration files""" if not text: return "" text = str(text) # Remove characters that could break JSON/config files text = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', text) text = re.sub(r'[{}[\]"]', '', text) # Escape forward slashes and backslashes text = text.replace('\\', '\\\\').replace('/', '\\/') # Truncate to reasonable length text = text[:max_length] return text.strip() def validate_input(input_type, value, **kwargs): """Validate and sanitize user input""" if value is None: value = "" if input_type == "task_name": return sanitize_csv_text(value) elif input_type == "notes": return sanitize_csv_text(value) elif input_type == "invoice_number": # Invoice numbers - allow alphanumeric, hyphens, underscores value = str(value) value = re.sub(r'[^\w\-]', '', value) return value.strip()[:50] or "INV001" elif input_type == "customer_name": return sanitize_config_text(value) elif input_type == "job_name": return sanitize_config_text(value) elif input_type == "file_path": return sanitize_filename(value) else: # Default sanitization return sanitize_csv_text(value) import re def test_sanitization(): """Test all sanitization functions with various malicious inputs""" print("🔒 Testing Input Sanitization Functions") print("=" * 60) # Test CSV sanitization print("\n📋 CSV Text Sanitization:") csv_tests = [ ("=SUM(1,2)", "CSV formula injection"), ("=1+1", "Excel formula injection"), ("-test", "Dash injection"), ("+dangerous", "Plus injection"), ("@malicious", "At sign injection"), ("normal text", "Normal text"), ("Text with tabs", "Tab characters"), ("Line\nbreaks\nhere", "Newline characters"), ("", "Empty string"), (None, "None value"), ("a" * 600, "Very long text (600 chars)"), (" spaced text ", "Leading/trailing spaces"), ("Text;with,commas", "Comma separated"), ("""Text with "quotes" and 'apostrophes'""", "Quote characters") ] for input_text, description in csv_tests: result = sanitize_csv_text(input_text) print(f" {description:30} | Input: '{str(input_text)[:30]}...' | Result: '{result}'") # Test filename sanitization print("\n📁 Filename Sanitization:") filename_tests = [ ("../../../etc/passwd", "Directory traversal"), ("<>:\"/\\?*", "Invalid filename characters"), ("normal_file.csv", "Normal filename"), ("file without extension", "Missing extension"), ("file.txt", "Wrong extension"), ("..hidden", "Hidden file"), ("", "Empty filename"), (None, "None filename"), ("a" * 200, "Very long filename"), (" spaced filename.csv ", "Spaced filename"), ("con.txt", "Windows reserved name"), ("file..csv", "Multiple dots") ] for input_path, description in filename_tests: result = sanitize_filename(input_path) print(f" {description:30} | Input: '{str(input_path)[:30]}...' | Result: '{result}'") # Test config text sanitization print("\n⚙️ Config Text Sanitization:") config_tests = [ ("{}[]\"\\", "JSON-breaking characters"), ("Normal Text", "Normal text"), ("\\Windows\\Path", "Windows path"), ("Unix/Path", "Unix path"), ("", "Empty text"), (None, "None text"), ("a" * 150, "Long text (150 chars)"), ("Text with\0control\0chars", "Control characters") ] for input_text, description in config_tests: result = sanitize_config_text(input_text) print(f" {description:30} | Input: '{str(input_text)[:30]}...' | Result: '{result}'") # Test validation function print("\n✅ Input Validation:") validation_tests = [ ("invoice_number", "=SUM(1,2)", "Invoice with formula"), ("invoice_number", "INV-2024-001", "Normal invoice"), ("invoice_number", "", "Empty invoice"), ("invoice_number", "!@#$%^&*()", "Special characters"), ("task_name", "=dangerous+formula", "Task with formula"), ("customer_name", "{evil:json}", "Customer with JSON"), ("job_name", "Windows/Path\\Issue", "Job with path chars") ] for input_type, input_val, description in validation_tests: result = validate_input(input_type, input_val) print(f" {description:30} | Result: '{str(input_val)[:30]}...' -> '{result}'") print("\n✨ Sanitization tests completed!") print("\n🛡️ Security Features:") print(" - CSV injection prevention") print(" - Excel formula blocking") print(" - Directory traversal protection") print(" - JSON/Config file safety") print(" - Filename character restriction") print(" - Length limits enforced") if __name__ == "__main__": test_sanitization()