nessus-parser 0.3.0

A parser for `.nessus` (v2) XML reports
Documentation
//! Parse errors.

/// Errors returned while parsing Nessus XML into typed structures.
#[derive(Debug, Clone)]
pub enum FormatError {
    /// A required XML attribute was not present.
    MissingAttribute(&'static str),
    /// A required XML tag was not present.
    MissingTag(&'static str),
    /// A tag expected to appear once was repeated.
    RepeatedTag(&'static str),
    /// A value had an unexpected shape.
    UnexpectedFormat(&'static str),
    /// An XML node kind was not expected at this position.
    UnexpectedNodeKind,
    /// Non-empty text was found where no text content is allowed.
    UnexpectedText(Box<str>),
    /// An unknown XML attribute was encountered.
    UnexpectedXmlAttribute(Box<str>),
    /// The root tag does not match `NessusClientData_v2`.
    UnsupportedVersion,
    /// Failed to parse an integer value.
    ParseInt(std::num::ParseIntError),
    /// Failed to parse XML.
    Xml(Box<roxmltree::Error>),
    /// Failed to parse date/time data via `jiff`.
    Jiff(jiff::Error),
    /// Failed to parse an IP address.
    IpAddrParse(std::net::AddrParseError),
    /// Failed to parse a boolean value.
    BoolParse(std::str::ParseBoolError),
    /// An unexpected XML node/tag was encountered.
    UnexpectedNode(Box<str>),
    /// A ping-method line in plugin output is not recognized.
    UnexpectedPingMethod(Box<str>),
    /// A dead-host reason in plugin output is not recognized.
    UnexpectedDeadHostReason(Box<str>),
    /// A TCP reply suffix in plugin output is not recognized.
    UnexpectedPingTcpResponse(Box<str>),
    /// Ping plugin output does not match any recognized format.
    UnexpectedPingFormat(Box<str>),
    /// A protocol string was not one of `tcp`, `udp`, or `icmp`.
    UnexpectedProtocol(Box<str>),
    /// A MAC address could not be parsed from `XX:XX:XX:XX:XX:XX`.
    MacAddressParse,
    /// A plugin type string/value was not recognized.
    UnexpectedPluginType(Box<str>),
    /// A severity string/value was not recognized.
    UnexpectedLevel(Box<str>),
    /// A plugin item required `plugin_output` but it was missing.
    MissingPluginOutput,
}

impl From<std::str::ParseBoolError> for FormatError {
    fn from(err: std::str::ParseBoolError) -> Self {
        Self::BoolParse(err)
    }
}

impl From<std::net::AddrParseError> for FormatError {
    fn from(err: std::net::AddrParseError) -> Self {
        Self::IpAddrParse(err)
    }
}

impl From<std::num::ParseIntError> for FormatError {
    fn from(err: std::num::ParseIntError) -> Self {
        Self::ParseInt(err)
    }
}

impl From<roxmltree::Error> for FormatError {
    fn from(err: roxmltree::Error) -> Self {
        Self::Xml(Box::from(err))
    }
}

impl From<jiff::Error> for FormatError {
    fn from(err: jiff::Error) -> Self {
        Self::Jiff(err)
    }
}

impl std::fmt::Display for FormatError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::MissingAttribute(attr) => {
                write!(f, "Missing attribute: {attr}")
            }
            Self::MissingTag(tag) => {
                write!(f, "Missing tag: {tag}")
            }
            Self::RepeatedTag(tag) => {
                write!(f, "Repeated tag: {tag}")
            }
            Self::UnexpectedFormat(s) => {
                write!(f, "Unexpected format: {s}")
            }
            Self::UnexpectedNodeKind => {
                write!(f, "Unexpected NodeKind")
            }
            Self::UnexpectedText(s) => {
                write!(f, "Unexpected text: {s}")
            }
            Self::UnexpectedNode(s) => {
                write!(f, "Unexpected node: {s}")
            }
            Self::UnexpectedXmlAttribute(s) => {
                write!(f, "Unexpected XML attributes: {s}")
            }
            Self::UnsupportedVersion => write!(f, "Unsupported version"),
            Self::UnexpectedPingMethod(s) => write!(f, "Unexpected ping method: {s}"),
            Self::UnexpectedDeadHostReason(s) => write!(f, "Unexpected dead host reason: {s}"),
            Self::UnexpectedPingTcpResponse(s) => write!(f, "Unexpected ping TCP response: {s}"),
            Self::UnexpectedPingFormat(s) => write!(f, "Unexpected ping format: {s}"),
            Self::UnexpectedProtocol(s) => write!(f, "Unexpected protocol: {s}"),
            Self::UnexpectedPluginType(s) => write!(f, "Unexpected plugin type: {s}"),
            Self::UnexpectedLevel(s) => write!(f, "Unexpected level: {s}"),
            Self::MissingPluginOutput => write!(f, "Missing plugin output"),
            Self::MacAddressParse => write!(f, "Can't parse MAC address"),
            Self::ParseInt(err) => write!(f, "{err}"),
            Self::Xml(err) => write!(f, "{err}"),
            Self::Jiff(err) => write!(f, "{err}"),
            Self::IpAddrParse(err) => write!(f, "{err}"),
            Self::BoolParse(err) => write!(f, "{err}"),
        }
    }
}

impl std::error::Error for FormatError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::ParseInt(err) => Some(err),
            Self::Xml(err) => Some(err),
            Self::Jiff(err) => Some(err),
            Self::IpAddrParse(err) => Some(err),
            Self::BoolParse(err) => Some(err),
            Self::MissingAttribute(_)
            | Self::MissingTag(_)
            | Self::RepeatedTag(_)
            | Self::UnexpectedFormat(_)
            | Self::UnexpectedNodeKind
            | Self::UnexpectedNode(_)
            | Self::UnexpectedText(_)
            | Self::UnexpectedXmlAttribute(_)
            | Self::UnsupportedVersion
            | Self::UnexpectedPingMethod(_)
            | Self::UnexpectedDeadHostReason(_)
            | Self::UnexpectedPingTcpResponse(_)
            | Self::UnexpectedPingFormat(_)
            | Self::UnexpectedProtocol(_)
            | Self::UnexpectedPluginType(_)
            | Self::UnexpectedLevel(_)
            | Self::MissingPluginOutput
            | Self::MacAddressParse => None,
        }
    }
}