ploit-malper 0.1.1

Post-exploitation analysis and vulnerability intelligence toolkit
Documentation
use crate::error::Result;
use crate::models::ScanRecord;
use serde_json::Value;

pub fn parse_vulnmalper_json(json_input: &str) -> Result<Vec<ScanRecord>> {
    let value: Value = serde_json::from_str(json_input)?;
    let findings = match value {
        Value::Array(arr) => parse_array(&arr),
        Value::Object(obj) => {
            if let Some(arr) = obj.get("results").and_then(Value::as_array) {
                parse_array(arr)
            } else if let Some(arr) = obj.get("findings").and_then(Value::as_array) {
                parse_array(arr)
            } else {
                Vec::new()
            }
        }
        _ => Vec::new(),
    };

    Ok(findings)
}

fn parse_array(arr: &[Value]) -> Vec<ScanRecord> {
    arr.iter()
        .filter_map(|v| {
            let target = v.get("target")?.as_str()?.to_string();
            let tool = v.get("tool")?.as_str()?.to_string();
            let title = v.get("title")?.as_str()?.to_string();
            let severity = v
                .get("severity")
                .and_then(Value::as_str)
                .unwrap_or("unknown")
                .to_string();
            let port = v
                .get("port")
                .and_then(Value::as_u64)
                .and_then(|port| u16::try_from(port).ok());
            let cve = v.get("cve").and_then(Value::as_str).map(ToOwned::to_owned);
            let service = v
                .get("service")
                .and_then(Value::as_str)
                .map(ToOwned::to_owned);

            Some(ScanRecord {
                target,
                tool,
                title,
                severity,
                port,
                cve,
                service,
                raw: v.clone(),
                ..Default::default()
            })
        })
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_results_array() {
        let input = r#"{"results":[{"target":"10.0.0.1","tool":"nmap","title":"OpenSSH","severity":"high"}]}"#;
        let records = parse_vulnmalper_json(input).unwrap();
        assert_eq!(records.len(), 1);
        assert_eq!(records[0].target, "10.0.0.1");
    }
}