dataprof_db/security/
utils.rs1pub fn sanitize_error_message(error_message: &str) -> String {
5 let mut sanitized = error_message.to_string();
6
7 let patterns_to_remove = [
8 r"postgresql://[^\s]+",
9 r"mysql://[^\s]+",
10 r"sqlite://[^\s]+",
11 r"password[=:]\s*[^\s;]+",
12 r"pass[=:]\s*[^\s;]+",
13 r"pwd[=:]\s*[^\s;]+",
14 r"Password [^:]*: ['\x22][^'\x22]+['\x22]",
15 r"verification failed: ['\x22][^'\x22]+['\x22]",
16 r"[A-Za-z]:\\[^\s]+",
17 r"/[^\s]*/.env[^\s]*",
18 r"/[^\s]*/config[^\s]*",
19 r"/home/[^\s/]+/[^\s]*",
20 r"/etc/[^\s]*",
21 r"\.[^\s]*conf[^\s]*",
22 r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b",
23 r"user[\s=:]['\x22]?[^'\x22\s;]+['\x22]?",
24 r"username[\s=:]['\x22]?[^'\x22\s;]+['\x22]?",
25 r"for user: [a-zA-Z0-9_]+",
26 r"failed for user: [a-zA-Z0-9_]+",
27 r"for username: ['\x22][^'\x22]+['\x22]",
28 r"denied for username: ['\x22][^'\x22]+['\x22]",
29 r"permission denied: ['\x22][^'\x22]+['\x22]",
30 r"User [^:]*: ['\x22][^'\x22]+['\x22]",
31 ];
32
33 for pattern in &patterns_to_remove {
34 if let Ok(regex) = regex::Regex::new(pattern) {
35 sanitized = regex.replace_all(&sanitized, "[REDACTED]").to_string();
36 }
37 }
38
39 if sanitized.len() > 500 {
40 sanitized = format!("{}... [truncated for security]", &sanitized[..500]);
41 }
42
43 sanitized
44}
45
46pub fn add_query_param(connection_string: String, key: &str, value: &str) -> String {
48 if connection_string.contains('?') {
49 format!("{}&{}={}", connection_string, key, value)
50 } else {
51 format!("{}?{}={}", connection_string, key, value)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn test_add_query_param() {
61 let base = "postgresql://user@host/db".to_string();
62 let result = add_query_param(base, "sslmode", "require");
63 assert_eq!(result, "postgresql://user@host/db?sslmode=require");
64
65 let with_existing = "postgresql://user@host/db?existing=value".to_string();
66 let result = add_query_param(with_existing, "sslmode", "require");
67 assert_eq!(
68 result,
69 "postgresql://user@host/db?existing=value&sslmode=require"
70 );
71 }
72
73 #[test]
74 fn test_error_message_sanitization() {
75 let error_with_password =
76 "Connection failed: postgresql://user:secret123@localhost:5432/db";
77 let sanitized = sanitize_error_message(error_with_password);
78 assert!(!sanitized.contains("secret123"));
79 assert!(sanitized.contains("[REDACTED]"));
80
81 let error_with_path = "Config file not found: C:\\Users\\admin\\.env";
82 let sanitized = sanitize_error_message(error_with_path);
83 assert!(sanitized.contains("[REDACTED]"));
84
85 let normal_error = "Table 'products' doesn't exist";
86 let sanitized = sanitize_error_message(normal_error);
87 assert_eq!(sanitized, normal_error);
88 }
89}