use crate::rng::SimpleRng;
pub fn cloudflare_turnstile_variation(input: &str) -> String {
let mut rng = SimpleRng::new();
let patterns = [
format!("{}-{}", input, generate_random_suffix(&mut rng)),
format!("{}_{}", input, generate_random_suffix(&mut rng)),
format!("cf-turnstile-{}", input),
format!("turnstile-{}-{}", input, generate_random_suffix(&mut rng)),
];
patterns[rng.next() as usize % patterns.len()].clone()
}
pub fn cloudflare_challenge_response(input: &str) -> String {
let mut rng = SimpleRng::new();
if input.contains("cf_clearance") || input.contains("__cf_bm") {
input
.chars()
.map(|c| {
match rng.next() % 10 {
0..=6 => c.to_string(),
7 => {
if c == '=' {
if rng.next() % 2 == 0 {
" = ".to_string()
} else {
"=".to_string()
}
} else {
c.to_string()
}
}
8 => {
if c == '_' && rng.next() % 3 == 0 {
"-".to_string()
} else if c == '-' && rng.next() % 3 == 0 {
"_".to_string()
} else {
c.to_string()
}
}
_ => c.to_string(),
}
})
.collect()
} else if input.contains("turnstile") || input.contains("challenge") {
let mut result = input.to_string();
if rng.next() % 2 == 0 {
result.push_str(&format!("-{}", generate_random_suffix(&mut rng)));
}
result
} else {
format!("{}-{}", input, generate_random_suffix(&mut rng))
}
}
pub fn tls_handshake_pattern(input: &str) -> String {
let mut rng = SimpleRng::new();
let separators = [":", ",", " ", "-"];
let separator = separators[rng.next() as usize % separators.len()];
input
.split(|c: char| [':', ',', ' ', '-'].contains(&c))
.enumerate()
.map(|(i, part)| {
if i > 0 {
format!("{}{}", separator, part)
} else {
part.to_string()
}
})
.collect::<Vec<_>>()
.join("")
}
pub fn canvas_fingerprint_variation(input: &str) -> String {
let mut rng = SimpleRng::new();
input
.chars()
.map(|c| {
match rng.next() % 15 {
0..=11 => c.to_string(),
12 => {
match c {
'0' => {
if rng.next() % 2 == 0 {
"O".to_string()
} else {
"0".to_string()
}
}
'1' => {
if rng.next() % 2 == 0 {
"l".to_string()
} else {
"1".to_string()
}
}
'O' => {
if rng.next() % 2 == 0 {
"0".to_string()
} else {
"O".to_string()
}
}
'l' => {
if rng.next() % 2 == 0 {
"1".to_string()
} else {
"l".to_string()
}
}
_ => c.to_string(),
}
}
13 => {
if c.is_whitespace() && rng.next() % 2 == 0 {
" ".to_string() } else {
c.to_string()
}
}
_ => c.to_string(),
}
})
.collect()
}
pub fn webgl_fingerprint_obfuscate(input: &str) -> String {
let mut rng = SimpleRng::new();
input
.chars()
.map(|c| {
match rng.next() % 12 {
0..=9 => c.to_string(),
10 => {
if c.is_ascii_digit() && rng.next() % 4 == 0 {
let digit = c.to_digit(10).unwrap();
let new_digit = (digit + 1) % 10;
char::from_digit(new_digit, 10).unwrap_or(c).to_string()
} else {
c.to_string()
}
}
_ => {
if c == '.' && rng.next() % 3 == 0 {
".".to_string()
} else if c.is_alphabetic() && rng.next() % 5 == 0 {
if c.is_uppercase() {
c.to_lowercase().to_string()
} else {
c.to_uppercase().to_string()
}
} else {
c.to_string()
}
}
}
})
.collect()
}
pub fn font_fingerprint_consistency(input: &str) -> String {
let mut rng = SimpleRng::new();
if input.is_empty() {
return input.to_string();
}
let fonts: Vec<&str> = input
.split(|c: char| [',', ';'].contains(&c))
.map(|s| s.trim())
.filter(|s| !s.is_empty())
.collect();
if fonts.is_empty() {
return input.to_string();
}
let separators = [", ", ",", "; ", ";"];
let separator = separators[rng.next() as usize % separators.len()];
fonts
.iter()
.enumerate()
.map(|(i, font)| {
let mut font_str = font.to_string();
if rng.next() % 4 == 0 && !font_str.starts_with('"') {
font_str = format!("\"{}\"", font_str);
}
if i > 0 {
format!("{}{}", separator, font_str)
} else {
font_str
}
})
.collect::<Vec<_>>()
.join("")
}
fn generate_random_suffix(rng: &mut SimpleRng) -> String {
let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
.chars()
.collect();
let length = 8 + (rng.next() % 8) as usize; (0..length)
.map(|_| chars[rng.next() as usize % chars.len()])
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cloudflare_turnstile_variation() {
let challenge = "challenge-token";
let result = cloudflare_turnstile_variation(challenge);
assert!(result.len() > challenge.len());
assert!(result.contains(challenge));
}
#[test]
fn test_cloudflare_challenge_response() {
let challenge = "cf_clearance=abc123";
let result = cloudflare_challenge_response(challenge);
assert!(result.len() > 0);
assert!(
result.to_lowercase().contains("cf_clearance")
|| result.to_lowercase().contains("cf-clearance")
);
}
#[test]
fn test_tls_handshake_pattern() {
let pattern = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256";
let result = tls_handshake_pattern(pattern);
assert!(result.len() > 0);
assert!(result.contains("TLS"));
}
#[test]
fn test_canvas_fingerprint_variation() {
let canvas_data = "canvas-fingerprint-data";
let result = canvas_fingerprint_variation(canvas_data);
assert!(result.len() > 0);
assert!(result.contains("canvas"));
}
#[test]
fn test_webgl_fingerprint_obfuscate() {
let webgl_data = "WebGL 2.0 Renderer: ANGLE";
let result = webgl_fingerprint_obfuscate(webgl_data);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("webgl"));
}
#[test]
fn test_font_fingerprint_consistency() {
let font_list = "Arial, Helvetica, Times New Roman";
let result = font_fingerprint_consistency(font_list);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("arial"));
}
#[test]
fn test_cloudflare_challenge_response_turnstile() {
let challenge = "turnstile-challenge-123";
let result = cloudflare_challenge_response(challenge);
assert!(result.len() > 0);
assert!(result.contains("turnstile") || result.contains("challenge"));
}
#[test]
fn test_cloudflare_challenge_response_generic() {
let challenge = "generic-challenge";
let result = cloudflare_challenge_response(challenge);
assert!(result.len() > 0);
assert!(result.contains(challenge));
}
#[test]
fn test_cloudflare_turnstile_variation_empty_string() {
let result = cloudflare_turnstile_variation("");
assert!(result.len() > 0);
}
#[test]
fn test_cloudflare_turnstile_variation_unicode() {
let challenge = "challenge-测试-токен";
let result = cloudflare_turnstile_variation(challenge);
assert!(result.contains(challenge));
}
#[test]
fn test_cloudflare_challenge_response_cf_bm() {
let challenge = "__cf_bm=cookie123";
let result = cloudflare_challenge_response(challenge);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("cf_bm") || result.to_lowercase().contains("cf-bm"));
}
#[test]
fn test_cloudflare_challenge_response_empty_string() {
let result = cloudflare_challenge_response("");
assert!(result.len() > 0);
}
#[test]
fn test_tls_handshake_pattern_empty_string() {
let result = tls_handshake_pattern("");
assert_eq!(result, "");
}
#[test]
fn test_tls_handshake_pattern_single_cipher() {
let pattern = "TLS_AES_256_GCM_SHA384";
let result = tls_handshake_pattern(pattern);
assert!(result.contains("TLS"));
}
#[test]
fn test_tls_handshake_pattern_comma_separated() {
let pattern = "TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256";
let result = tls_handshake_pattern(pattern);
assert!(result.contains("TLS"));
}
#[test]
fn test_tls_handshake_pattern_space_separated() {
let pattern = "TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256";
let result = tls_handshake_pattern(pattern);
assert!(result.contains("TLS"));
}
#[test]
fn test_canvas_fingerprint_variation_empty_string() {
let result = canvas_fingerprint_variation("");
assert_eq!(result, "");
}
#[test]
fn test_canvas_fingerprint_variation_unicode() {
let canvas_data = "canvas-测试-data";
let result = canvas_fingerprint_variation(canvas_data);
assert!(result.len() > 0);
}
#[test]
fn test_canvas_fingerprint_variation_preserves_length_approximately() {
let canvas_data = "test123";
let result = canvas_fingerprint_variation(canvas_data);
assert!(result.len() >= canvas_data.len() - 2);
assert!(result.len() <= canvas_data.len() + 2);
}
#[test]
fn test_webgl_fingerprint_obfuscate_empty_string() {
let result = webgl_fingerprint_obfuscate("");
assert_eq!(result, "");
}
#[test]
fn test_webgl_fingerprint_obfuscate_with_version() {
let webgl_data = "WebGL 2.0";
let result = webgl_fingerprint_obfuscate(webgl_data);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("webgl"));
}
#[test]
fn test_webgl_fingerprint_obfuscate_preserves_structure() {
let webgl_data = "WebGL 2.0 Renderer: ANGLE";
let result = webgl_fingerprint_obfuscate(webgl_data);
assert!(result.to_lowercase().contains("webgl"));
assert!(result.to_lowercase().contains("renderer"));
}
#[test]
fn test_font_fingerprint_consistency_empty_string() {
let result = font_fingerprint_consistency("");
assert_eq!(result, "");
}
#[test]
fn test_font_fingerprint_consistency_single_font() {
let font_list = "Arial";
let result = font_fingerprint_consistency(font_list);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("arial"));
}
#[test]
fn test_font_fingerprint_consistency_semicolon_separated() {
let font_list = "Arial; Helvetica; Times New Roman";
let result = font_fingerprint_consistency(font_list);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("arial"));
}
#[test]
fn test_font_fingerprint_consistency_preserves_fonts() {
let font_list = "Arial, Helvetica, Times New Roman";
let result = font_fingerprint_consistency(font_list);
assert!(result.to_lowercase().contains("arial"));
assert!(result.to_lowercase().contains("helvetica"));
assert!(result.to_lowercase().contains("times"));
}
#[test]
fn test_cloudflare_turnstile_variation_multiple_calls() {
let challenge = "test-challenge";
let results: Vec<String> = (0..10)
.map(|_| cloudflare_turnstile_variation(challenge))
.collect();
for result in &results {
assert!(result.contains(challenge));
}
let unique_results: std::collections::HashSet<&String> = results.iter().collect();
assert!(unique_results.len() >= 1);
}
#[test]
fn test_cloudflare_challenge_response_special_characters() {
let challenge = "cf_clearance=abc!@#$%^&*()123";
let result = cloudflare_challenge_response(challenge);
assert!(result.len() > 0);
assert!(
result.to_lowercase().contains("cf_clearance")
|| result.to_lowercase().contains("cf-clearance")
);
}
#[test]
fn test_tls_handshake_pattern_preserves_ciphers() {
let pattern = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256";
let result = tls_handshake_pattern(pattern);
assert!(result.contains("TLS_AES_256_GCM_SHA384"));
assert!(result.contains("TLS_CHACHA20_POLY1305_SHA256"));
}
#[test]
fn test_cloudflare_turnstile_variation_long_string() {
let challenge = "a".repeat(1000);
let result = cloudflare_turnstile_variation(&challenge);
assert!(result.len() > challenge.len());
assert!(result.contains(&challenge));
}
#[test]
fn test_cloudflare_challenge_response_long_string() {
let challenge = "cf_clearance=".to_string() + &"a".repeat(500);
let result = cloudflare_challenge_response(&challenge);
assert!(result.len() > 0);
assert!(
result.to_lowercase().contains("cf_clearance")
|| result.to_lowercase().contains("cf-clearance")
);
}
#[test]
fn test_tls_handshake_pattern_long_list() {
let pattern = (0..20)
.map(|i| format!("TLS_CIPHER_{}", i))
.collect::<Vec<_>>()
.join(":");
let result = tls_handshake_pattern(&pattern);
assert!(result.len() > 0);
assert!(result.contains("TLS_CIPHER_0"));
assert!(result.contains("TLS_CIPHER_19"));
}
#[test]
fn test_canvas_fingerprint_variation_special_chars_only() {
let canvas_data = "!@#$%^&*()";
let result = canvas_fingerprint_variation(canvas_data);
assert!(result.len() > 0);
}
#[test]
fn test_webgl_fingerprint_obfuscate_long_string() {
let webgl_data = "WebGL ".to_string() + &"2.0 ".repeat(100);
let result = webgl_fingerprint_obfuscate(&webgl_data);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("webgl"));
}
#[test]
fn test_font_fingerprint_consistency_long_list() {
let fonts: Vec<String> = (0..50).map(|i| format!("Font{}", i)).collect();
let font_list = fonts.join(", ");
let result = font_fingerprint_consistency(&font_list);
assert!(result.len() > 0);
assert!(result.to_lowercase().contains("font0"));
assert!(result.to_lowercase().contains("font49"));
}
#[test]
fn test_cloudflare_turnstile_variation_randomness() {
let challenge = "test-challenge";
let mut results = std::collections::HashSet::new();
for _ in 0..50 {
results.insert(cloudflare_turnstile_variation(challenge));
}
assert!(results.len() >= 1);
}
#[test]
fn test_cloudflare_challenge_response_randomness() {
let challenge = "cf_clearance=test123";
let mut results = std::collections::HashSet::new();
for _ in 0..50 {
results.insert(cloudflare_challenge_response(challenge));
}
assert!(results.len() >= 1);
}
#[test]
fn test_tls_handshake_pattern_variation() {
let pattern = "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256";
let mut results = std::collections::HashSet::new();
for _ in 0..20 {
results.insert(tls_handshake_pattern(pattern));
}
assert!(results.len() >= 1);
}
#[test]
fn test_font_fingerprint_consistency_variation() {
let font_list = "Arial, Helvetica";
let mut results = std::collections::HashSet::new();
for _ in 0..20 {
results.insert(font_fingerprint_consistency(font_list));
}
assert!(results.len() >= 1);
}
#[test]
fn test_cloudflare_functions_preserve_non_empty_output() {
let test_cases = vec![
"test",
"challenge-token-123",
"cf_clearance=abc",
"TLS_AES_256_GCM_SHA384",
"canvas-data",
"WebGL 2.0",
"Arial, Helvetica",
];
for input in test_cases {
assert!(
cloudflare_turnstile_variation(input).len() > 0,
"turnstile failed for: {}",
input
);
assert!(
cloudflare_challenge_response(input).len() > 0,
"challenge_response failed for: {}",
input
);
let _ = tls_handshake_pattern(input);
let _ = canvas_fingerprint_variation(input);
let _ = webgl_fingerprint_obfuscate(input);
let _ = font_fingerprint_consistency(input);
}
}
#[test]
fn test_cloudflare_challenge_response_all_cookie_formats() {
let formats = vec![
"cf_clearance=token123",
"__cf_bm=cookie456",
"cf-clearance=token789",
"__cf-bm=cookie012",
];
for format in formats {
let result = cloudflare_challenge_response(format);
assert!(result.len() > 0, "Failed for format: {}", format);
let lower = result.to_lowercase();
assert!(
lower.contains("cf") || lower.contains("clearance") || lower.contains("bm"),
"Result doesn't contain cookie identifier: {}",
result
);
}
}
}