use serde::Deserialize;
use std::fs;
use std::path::Path;
#[derive(Deserialize)]
struct ProbesFile {
baseline_payload: String,
baseline_description: String,
sql_keywords: Vec<String>,
sql_operators: Vec<String>,
sql_comments: Vec<String>,
sql_tautologies: Vec<String>,
#[serde(default)]
xss_tag: Vec<TagOrFn>,
xss_events: Vec<String>,
#[serde(default)]
xss_function: Vec<TagOrFn>,
command_separators: Vec<String>,
command_names: Vec<String>,
command_paths: Vec<String>,
}
#[derive(Deserialize)]
struct TagOrFn {
name: String,
payload: String,
expected_blocked: bool,
}
fn emit_str_array(out: &mut String, name: &str, values: &[String]) {
out.push_str(&format!("pub(crate) const {name}: &[&str] = &[\n"));
for v in values {
out.push_str(&format!(" {v:?},\n"));
}
out.push_str("];\n\n");
}
fn emit_tagfn_array(out: &mut String, name: &str, values: &[TagOrFn]) {
out.push_str(&format!(
"pub(crate) const {name}: &[(&str, &str, bool)] = &[\n"
));
for e in values {
out.push_str(&format!(
" ({:?}, {:?}, {}),\n",
e.name, e.payload, e.expected_blocked
));
}
out.push_str("];\n\n");
}
fn main() {
let in_path = Path::new("rules/probes/differential.toml");
let out_dir = std::env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir).join("differential_data.rs");
let raw =
fs::read_to_string(in_path).unwrap_or_else(|e| panic!("read {}: {e}", in_path.display()));
let parsed: ProbesFile =
toml::from_str(&raw).unwrap_or_else(|e| panic!("parse {}: {e}", in_path.display()));
let mut out = String::with_capacity(8192);
out.push_str(
"// Auto-generated by build.rs from rules/probes/differential.toml — do not edit.\n\n",
);
out.push_str(&format!(
"pub(crate) const BASELINE_PAYLOAD: &str = {:?};\n",
parsed.baseline_payload
));
out.push_str(&format!(
"pub(crate) const BASELINE_DESCRIPTION: &str = {:?};\n\n",
parsed.baseline_description
));
emit_str_array(&mut out, "SQL_KEYWORDS", &parsed.sql_keywords);
emit_str_array(&mut out, "SQL_OPERATORS", &parsed.sql_operators);
emit_str_array(&mut out, "SQL_COMMENTS", &parsed.sql_comments);
emit_str_array(&mut out, "SQL_TAUTOLOGIES", &parsed.sql_tautologies);
emit_tagfn_array(&mut out, "XSS_TAGS", &parsed.xss_tag);
emit_str_array(&mut out, "XSS_EVENTS", &parsed.xss_events);
emit_tagfn_array(&mut out, "XSS_FUNCTIONS", &parsed.xss_function);
emit_str_array(&mut out, "COMMAND_SEPARATORS", &parsed.command_separators);
emit_str_array(&mut out, "COMMAND_NAMES", &parsed.command_names);
emit_str_array(&mut out, "COMMAND_PATHS", &parsed.command_paths);
fs::write(&out_path, out).expect("write differential_data.rs");
println!("cargo::rerun-if-changed={}", in_path.display());
}