mod common; use bspds::image::{ImageError, ImageProcessor}; use bspds::comms::{SendError, is_valid_phone_number, sanitize_header_value}; use bspds::oauth::templates::{error_page, login_page, success_page}; #[test] fn test_header_injection_sanitization() { let malicious = "Injected\r\nBcc: attacker@evil.com"; let sanitized = sanitize_header_value(malicious); assert!(!sanitized.contains('\r') && !sanitized.contains('\n')); assert!(sanitized.contains("Injected") && sanitized.contains("Bcc:")); let normal = "Normal Subject Line"; assert_eq!(sanitize_header_value(normal), "Normal Subject Line"); let padded = " Subject "; assert_eq!(sanitize_header_value(padded), "Subject"); let multi_newline = "Line1\r\nLine2\nLine3\rLine4"; let sanitized = sanitize_header_value(multi_newline); assert!(!sanitized.contains('\r') && !sanitized.contains('\n')); assert!(sanitized.contains("Line1") && sanitized.contains("Line4")); let header_injection = "Normal Subject\r\nBcc: attacker@evil.com\r\nX-Injected: value"; let sanitized = sanitize_header_value(header_injection); assert_eq!(sanitized.split("\r\n").count(), 1); assert!(sanitized.contains("Normal Subject") && sanitized.contains("Bcc:") && sanitized.contains("X-Injected:")); let with_null = "client\0id"; assert!(sanitize_header_value(with_null).contains("client")); let long_input = "x".repeat(10000); assert!(!sanitize_header_value(&long_input).is_empty()); } #[test] fn test_phone_number_validation() { assert!(is_valid_phone_number("+1234567890")); assert!(is_valid_phone_number("+12025551234")); assert!(is_valid_phone_number("+442071234567")); assert!(is_valid_phone_number("+4915123456789")); assert!(is_valid_phone_number("+1")); assert!(!is_valid_phone_number("1234567890")); assert!(!is_valid_phone_number("12025551234")); assert!(!is_valid_phone_number("")); assert!(!is_valid_phone_number("+")); assert!(!is_valid_phone_number("+12345678901234567890123")); assert!(!is_valid_phone_number("+abc123")); assert!(!is_valid_phone_number("+1234abc")); assert!(!is_valid_phone_number("+a")); assert!(!is_valid_phone_number("+1234 5678")); assert!(!is_valid_phone_number("+ 1234567890")); assert!(!is_valid_phone_number("+1 ")); assert!(!is_valid_phone_number("+123-456-7890")); assert!(!is_valid_phone_number("+1(234)567890")); assert!(!is_valid_phone_number("+1.234.567.890")); for malicious in ["+123; rm -rf /", "+123 && cat /etc/passwd", "+123`id`", "+123$(whoami)", "+123|cat /etc/shadow", "+123\n--help", "+123\r\n--version", "+123--help"] { assert!(!is_valid_phone_number(malicious), "Command injection '{}' should be rejected", malicious); } } #[test] fn test_image_file_size_limits() { let processor = ImageProcessor::new(); let oversized_data: Vec = vec![0u8; 11 * 1024 * 1024]; let result = processor.process(&oversized_data, "image/jpeg"); match result { Err(ImageError::FileTooLarge { .. }) => {} Err(other) => { let msg = format!("{:?}", other); if !msg.to_lowercase().contains("size") && !msg.to_lowercase().contains("large") { panic!("Expected FileTooLarge error, got: {:?}", other); } } Ok(_) => panic!("Should reject files over size limit"), } let processor = ImageProcessor::new().with_max_file_size(1024); let data: Vec = vec![0u8; 2048]; assert!(processor.process(&data, "image/jpeg").is_err()); } #[test] fn test_oauth_template_xss_protection() { let html = login_page("", None, None, "test-uri", None, None); assert!(!html.contains(""), "test-uri", None, None); assert!(!html.contains(""), None); assert!(!html.contains("", Some("")); assert!(!html.contains("")); assert!(!html.contains("