pub use super::EveReader;
pub type EveJson = serde_json::Value;
pub trait Eve {
fn timestamp(&self) -> Option<chrono::DateTime<chrono::Utc>>;
fn add_tag(&mut self, tag: &str);
}
impl Eve for EveJson {
fn timestamp(&self) -> Option<chrono::DateTime<chrono::Utc>> {
if let EveJson::String(ts) = &self["timestamp"] {
if let Ok(dt) = parse_eve_timestamp(ts) {
return Some(dt);
}
}
None
}
fn add_tag(&mut self, tag: &str) {
if let EveJson::Null = self["tags"] {
self["tags"] = EveJson::Array(vec![]);
}
if let EveJson::Array(ref mut tags) = &mut self["tags"] {
tags.push(tag.into());
}
}
}
pub fn add_evebox_metadata(event: &mut EveJson, filename: Option<String>) {
if let EveJson::Null = event["evebox"] {
event["evebox"] = serde_json::json!({});
}
if let EveJson::Object(_) = &event["evebox"] {
if let Some(filename) = filename {
event["evebox"]["filename"] = filename.into();
}
}
event["tags"] = serde_json::json!([]);
}
pub fn parse_eve_timestamp(
s: &str,
) -> Result<chrono::DateTime<chrono::Utc>, Box<dyn std::error::Error + Sync + Send>> {
let s = s.replace("Z", "-0000");
let dt = chrono::DateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.6f%z")?;
Ok(dt.with_timezone(&chrono::Utc))
}
#[cfg(test)]
mod test {
#[test]
fn test_parse_eve_timestamp() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let ts = "2016-09-17T17:19:39.787733+0000";
let _dt = super::parse_eve_timestamp(ts)?;
let ts = "2016-09-17T17:19:39.787733-0000";
let _dt = super::parse_eve_timestamp(ts)?;
let ts = "2020-04-06T10:48:55.011800-0600";
let _dt = super::parse_eve_timestamp(ts)?;
let ts = "2020-04-06T10:48:55.011800+0600";
let _dt = super::parse_eve_timestamp(ts)?;
let ts: &str = "2020-04-06T10:48:55.011800Z";
let dt = super::parse_eve_timestamp(ts);
assert!(dt.is_ok());
let ts: &str = "2020-04-06T10:48:55.011Z";
let dt = super::parse_eve_timestamp(ts);
assert!(dt.is_ok());
Ok(())
}
}