pub fn has_nearby_user_input(lines: &[&str], line_num: usize, window: usize) -> bool {
let start = line_num.saturating_sub(window);
let end = (line_num + window + 1).min(lines.len());
lines[start..end].iter().any(|l| {
l.contains("req.") || l.contains("request.") || l.contains("r.URL")
|| l.contains(".body") || l.contains(".query") || l.contains(".params")
|| l.contains("getParameter") || l.contains("FormValue")
|| l.contains("getInputStream") || l.contains("PostForm")
|| l.contains("getHeader") || l.contains("r.Form")
|| l.contains("user_input") || l.contains("userInput")
|| l.contains("user_data") || l.contains("userData")
|| l.contains("payload")
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_finds_request_on_nearby_line() {
let lines = vec![
"func handle(w http.ResponseWriter, r *http.Request) {",
" cmd := r.FormValue(\"command\")",
" // some processing",
" exec.Command(cmd).Run()",
];
assert!(has_nearby_user_input(&lines, 3, 5));
}
#[test]
fn test_no_match_without_user_input() {
let lines = vec![
"func processFile() {",
" data := readConfig()",
" exec.Command(\"ls\").Run()",
];
assert!(!has_nearby_user_input(&lines, 2, 5));
}
#[test]
fn test_window_boundary() {
let lines = vec![
"req := request.getParameter(\"id\")",
"", "", "", "", "", "", "", "", "", "",
"exec.Command(cmd).Run()",
];
assert!(!has_nearby_user_input(&lines, 11, 5));
assert!(has_nearby_user_input(&lines, 11, 15));
}
#[test]
fn test_does_not_match_generic_words() {
let lines = vec![
"let metadata = process_formatted_data(records);",
"exec.Command(\"ls\").Run()",
];
assert!(!has_nearby_user_input(&lines, 1, 5));
}
}