Skip to main content

ploit_malper/engine/
parser.rs

1use crate::error::Result;
2use crate::models::ScanRecord;
3use serde_json::Value;
4
5pub fn parse_vulnmalper_json(json_input: &str) -> Result<Vec<ScanRecord>> {
6    let value: Value = serde_json::from_str(json_input)?;
7    let findings = match value {
8        Value::Array(arr) => parse_array(&arr),
9        Value::Object(obj) => {
10            if let Some(arr) = obj.get("results").and_then(Value::as_array) {
11                parse_array(arr)
12            } else if let Some(arr) = obj.get("findings").and_then(Value::as_array) {
13                parse_array(arr)
14            } else {
15                Vec::new()
16            }
17        }
18        _ => Vec::new(),
19    };
20
21    Ok(findings)
22}
23
24fn parse_array(arr: &[Value]) -> Vec<ScanRecord> {
25    arr.iter()
26        .filter_map(|v| {
27            let target = v.get("target")?.as_str()?.to_string();
28            let tool = v.get("tool")?.as_str()?.to_string();
29            let title = v.get("title")?.as_str()?.to_string();
30            let severity = v
31                .get("severity")
32                .and_then(Value::as_str)
33                .unwrap_or("unknown")
34                .to_string();
35            let port = v
36                .get("port")
37                .and_then(Value::as_u64)
38                .and_then(|port| u16::try_from(port).ok());
39            let cve = v.get("cve").and_then(Value::as_str).map(ToOwned::to_owned);
40            let service = v
41                .get("service")
42                .and_then(Value::as_str)
43                .map(ToOwned::to_owned);
44
45            Some(ScanRecord {
46                target,
47                tool,
48                title,
49                severity,
50                port,
51                cve,
52                service,
53                raw: v.clone(),
54                ..Default::default()
55            })
56        })
57        .collect()
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn parses_results_array() {
66        let input = r#"{"results":[{"target":"10.0.0.1","tool":"nmap","title":"OpenSSH","severity":"high"}]}"#;
67        let records = parse_vulnmalper_json(input).unwrap();
68        assert_eq!(records.len(), 1);
69        assert_eq!(records[0].target, "10.0.0.1");
70    }
71}