diff --git a/src/afterfact.rs b/src/afterfact.rs index dd1ae5fb..2be77936 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -72,19 +72,26 @@ pub fn after_fact() { } fn emit_csv(writer: &mut W, displayflag: bool) -> io::Result<()> { - let mut wtr = csv::WriterBuilder::new().from_writer(writer); + let mut wtr; + if displayflag { + wtr = csv::WriterBuilder::new() + .delimiter(b'|') + .from_writer(writer); + } else { + wtr = csv::WriterBuilder::new().from_writer(writer); + } let messages = print::MESSAGES.lock().unwrap(); let mut detect_count = 0; for (time, detect_infos) in messages.iter() { for detect_info in detect_infos { if displayflag { wtr.serialize(DisplayFormat { - time: &format_time(time), - level: &detect_info.level, - computername: &detect_info.computername, - eventid: &detect_info.eventid, - alert: &detect_info.alert, - details: &detect_info.detail, + time: &format!("{} ", &format_time(time)), + level: &format!(" {} ", &detect_info.level), + computername: &format!(" {} ", &detect_info.computername), + eventid: &format!(" {} ", &detect_info.eventid), + alert: &format!(" {} ", &detect_info.alert), + details: &format!(" {}", &detect_info.detail), })?; } else { // csv出力時フォーマット @@ -131,81 +138,165 @@ where } } -#[test] -fn test_emit_csv() { +#[cfg(test)] +mod tests { + use crate::afterfact::emit_csv; + use crate::detections::print; + use chrono::{Local, TimeZone, Utc}; use serde_json::Value; + use std::fs::File; use std::fs::{read_to_string, remove_file}; - let testfilepath: &str = "test.evtx"; - let testrulepath: &str = "test-rule.yml"; - let test_title = "test_title"; - let test_level = "high"; - let test_computername = "testcomputer"; - let test_eventid = "1111"; - let output = "pokepoke"; - { - let mut messages = print::MESSAGES.lock().unwrap(); + use std::io; - let val = r##" - { - "Event": { - "EventData": { - "CommandRLine": "hoge" - }, - "System": { - "TimeCreated_attributes": { - "SystemTime": "1996-02-27T01:05:01Z" - } - } - } - } - "##; - let event: Value = serde_json::from_str(val).unwrap(); - messages.insert( - testfilepath.to_string(), - testrulepath.to_string(), - &event, - test_level.to_string(), - test_computername.to_string(), - test_eventid.to_string(), - test_title.to_string(), - output.to_string(), - ); + #[test] + fn test_emit_csv() { + //テストの並列処理によって読み込みの順序が担保できずstatic変数の内容が担保が取れない為、このテストはシーケンシャルで行う + test_emit_csv_output(); + test_emit_csv_output(); } - let expect_time = Utc - .datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ") - .unwrap(); - let expect_tz = expect_time.with_timezone(&Local); - let expect = "Time,Computername,Eventid,Level,Alert,Details,Rulepath,Filepath\n".to_string() - + &expect_tz - .clone() - .format("%Y-%m-%d %H:%M:%S%.3f %:z") - .to_string() - + "," - + test_computername - + "," - + test_eventid - + "," - + test_level - + "," - + test_title - + "," - + output - + "," - + testrulepath - + "," - + &testfilepath.to_string() - + "\n"; - - let mut file: Box = - Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap()); - assert!(emit_csv(&mut file, false).is_ok()); - - match read_to_string("./test_emit_csv.csv") { - Err(_) => panic!("Failed to open file."), - Ok(s) => { - assert_eq!(s, expect); + fn test_emit_csv_output() { + let testfilepath: &str = "test.evtx"; + let testrulepath: &str = "test-rule.yml"; + let test_title = "test_title"; + let test_level = "high"; + let test_computername = "testcomputer"; + let test_eventid = "1111"; + let output = "pokepoke"; + { + let mut messages = print::MESSAGES.lock().unwrap(); + messages.clear(); + let val = r##" + { + "Event": { + "EventData": { + "CommandRLine": "hoge" + }, + "System": { + "TimeCreated_attributes": { + "SystemTime": "1996-02-27T01:05:01Z" + } + } + } + } + "##; + let event: Value = serde_json::from_str(val).unwrap(); + messages.insert( + testfilepath.to_string(), + testrulepath.to_string(), + &event, + test_level.to_string(), + test_computername.to_string(), + test_eventid.to_string(), + test_title.to_string(), + output.to_string(), + ); } - }; - assert!(remove_file("./test_emit_csv.csv").is_ok()); + let expect_time = Utc + .datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ") + .unwrap(); + let expect_tz = expect_time.with_timezone(&Local); + let expect = "Time,Computername,Eventid,Level,Alert,Details,Rulepath,Filepath\n" + .to_string() + + &expect_tz + .clone() + .format("%Y-%m-%d %H:%M:%S%.3f %:z") + .to_string() + + "," + + test_computername + + "," + + test_eventid + + "," + + test_level + + "," + + test_title + + "," + + output + + "," + + testrulepath + + "," + + &testfilepath.to_string() + + "\n"; + let mut file: Box = + Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap()); + assert!(emit_csv(&mut file, false).is_ok()); + match read_to_string("./test_emit_csv.csv") { + Err(_) => panic!("Failed to open file."), + Ok(s) => { + assert_eq!(s, expect); + } + }; + assert!(remove_file("./test_emit_csv.csv").is_ok()); + check_emit_csv_display(); + } + + fn check_emit_csv_display() { + let testfilepath: &str = "test2.evtx"; + let testrulepath: &str = "test-rule2.yml"; + let test_title = "test_title2"; + let test_level = "medium"; + let test_computername = "testcomputer2"; + let test_eventid = "2222"; + let output = "displaytest"; + { + let mut messages = print::MESSAGES.lock().unwrap(); + messages.clear(); + let val = r##" + { + "Event": { + "EventData": { + "CommandRLine": "hoge" + }, + "System": { + "TimeCreated_attributes": { + "SystemTime": "1996-02-27T01:05:01Z" + } + } + } + } + "##; + let event: Value = serde_json::from_str(val).unwrap(); + messages.insert( + testfilepath.to_string(), + testrulepath.to_string(), + &event, + test_level.to_string(), + test_computername.to_string(), + test_eventid.to_string(), + test_title.to_string(), + output.to_string(), + ); + messages.debug(); + } + let expect_time = Utc + .datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ") + .unwrap(); + let expect_tz = expect_time.with_timezone(&Local); + let expect = "Time|Computername|Eventid|Level|Alert|Details\n".to_string() + + &expect_tz + .clone() + .format("%Y-%m-%d %H:%M:%S%.3f %:z") + .to_string() + + " | " + + test_computername + + " | " + + test_eventid + + " | " + + test_level + + " | " + + test_title + + " | " + + output + + "\n"; + let mut file: Box = + Box::new(File::create("./test_emit_csv_display.txt".to_string()).unwrap()); + assert!(emit_csv(&mut file, true).is_ok()); + match read_to_string("./test_emit_csv_display.txt") { + Err(_) => panic!("Failed to open file."), + Ok(s) => { + assert_eq!(s, expect); + } + }; + assert!(remove_file("./test_emit_csv_display.txt").is_ok()); + } } diff --git a/src/detections/detection.rs b/src/detections/detection.rs index b103a742..8012f1b9 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -151,9 +151,9 @@ impl Detection { "Medium", "Low", "Informational", - "Undeifned", + "Undefined", ]); - // levclcounts is [(Undeifned), (Informational), (Low),(Medium),(High),(Critical)] + // levclcounts is [(Undefined), (Informational), (Low),(Medium),(High),(Critical)] let mut levelcounts = Vec::from([0, 0, 0, 0, 0, 0]); for rule in rules.into_iter() { if rule.check_exist_countdata() { diff --git a/src/detections/print.rs b/src/detections/print.rs index 95563ecc..e489587b 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -188,6 +188,11 @@ impl Message { return Option::Some(datetime.unwrap()); } } + + /// message内のマップをクリアする。テストする際の冪等性の担保のため作成。 + pub fn clear(&mut self) { + self.map.clear(); + } } impl AlertMessage {