* changed stdout result delimiter #244 * removed unnecessary space #244 * added display output test #244 - added static map clear function (only test use) - added outputformat test case of stdout (change sequencial process in emit_csv test To prevent the contents of static variables from changing depending on the order of execution) * fixed typo
This commit is contained in:
119
src/afterfact.rs
119
src/afterfact.rs
@@ -72,19 +72,26 @@ pub fn after_fact() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emit_csv<W: std::io::Write>(writer: &mut W, displayflag: bool) -> io::Result<()> {
|
fn emit_csv<W: std::io::Write>(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 messages = print::MESSAGES.lock().unwrap();
|
||||||
let mut detect_count = 0;
|
let mut detect_count = 0;
|
||||||
for (time, detect_infos) in messages.iter() {
|
for (time, detect_infos) in messages.iter() {
|
||||||
for detect_info in detect_infos {
|
for detect_info in detect_infos {
|
||||||
if displayflag {
|
if displayflag {
|
||||||
wtr.serialize(DisplayFormat {
|
wtr.serialize(DisplayFormat {
|
||||||
time: &format_time(time),
|
time: &format!("{} ", &format_time(time)),
|
||||||
level: &detect_info.level,
|
level: &format!(" {} ", &detect_info.level),
|
||||||
computername: &detect_info.computername,
|
computername: &format!(" {} ", &detect_info.computername),
|
||||||
eventid: &detect_info.eventid,
|
eventid: &format!(" {} ", &detect_info.eventid),
|
||||||
alert: &detect_info.alert,
|
alert: &format!(" {} ", &detect_info.alert),
|
||||||
details: &detect_info.detail,
|
details: &format!(" {}", &detect_info.detail),
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
// csv出力時フォーマット
|
// csv出力時フォーマット
|
||||||
@@ -131,10 +138,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_emit_csv() {
|
mod tests {
|
||||||
|
use crate::afterfact::emit_csv;
|
||||||
|
use crate::detections::print;
|
||||||
|
use chrono::{Local, TimeZone, Utc};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use std::fs::File;
|
||||||
use std::fs::{read_to_string, remove_file};
|
use std::fs::{read_to_string, remove_file};
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emit_csv() {
|
||||||
|
//テストの並列処理によって読み込みの順序が担保できずstatic変数の内容が担保が取れない為、このテストはシーケンシャルで行う
|
||||||
|
test_emit_csv_output();
|
||||||
|
test_emit_csv_output();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_emit_csv_output() {
|
||||||
let testfilepath: &str = "test.evtx";
|
let testfilepath: &str = "test.evtx";
|
||||||
let testrulepath: &str = "test-rule.yml";
|
let testrulepath: &str = "test-rule.yml";
|
||||||
let test_title = "test_title";
|
let test_title = "test_title";
|
||||||
@@ -144,7 +165,7 @@ fn test_emit_csv() {
|
|||||||
let output = "pokepoke";
|
let output = "pokepoke";
|
||||||
{
|
{
|
||||||
let mut messages = print::MESSAGES.lock().unwrap();
|
let mut messages = print::MESSAGES.lock().unwrap();
|
||||||
|
messages.clear();
|
||||||
let val = r##"
|
let val = r##"
|
||||||
{
|
{
|
||||||
"Event": {
|
"Event": {
|
||||||
@@ -171,12 +192,12 @@ fn test_emit_csv() {
|
|||||||
output.to_string(),
|
output.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let expect_time = Utc
|
let expect_time = Utc
|
||||||
.datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ")
|
.datetime_from_str("1996-02-27T01:05:01Z", "%Y-%m-%dT%H:%M:%SZ")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expect_tz = expect_time.with_timezone(&Local);
|
let expect_tz = expect_time.with_timezone(&Local);
|
||||||
let expect = "Time,Computername,Eventid,Level,Alert,Details,Rulepath,Filepath\n".to_string()
|
let expect = "Time,Computername,Eventid,Level,Alert,Details,Rulepath,Filepath\n"
|
||||||
|
.to_string()
|
||||||
+ &expect_tz
|
+ &expect_tz
|
||||||
.clone()
|
.clone()
|
||||||
.format("%Y-%m-%d %H:%M:%S%.3f %:z")
|
.format("%Y-%m-%d %H:%M:%S%.3f %:z")
|
||||||
@@ -196,11 +217,9 @@ fn test_emit_csv() {
|
|||||||
+ ","
|
+ ","
|
||||||
+ &testfilepath.to_string()
|
+ &testfilepath.to_string()
|
||||||
+ "\n";
|
+ "\n";
|
||||||
|
|
||||||
let mut file: Box<dyn io::Write> =
|
let mut file: Box<dyn io::Write> =
|
||||||
Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap());
|
Box::new(File::create("./test_emit_csv.csv".to_string()).unwrap());
|
||||||
assert!(emit_csv(&mut file, false).is_ok());
|
assert!(emit_csv(&mut file, false).is_ok());
|
||||||
|
|
||||||
match read_to_string("./test_emit_csv.csv") {
|
match read_to_string("./test_emit_csv.csv") {
|
||||||
Err(_) => panic!("Failed to open file."),
|
Err(_) => panic!("Failed to open file."),
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
@@ -208,4 +227,76 @@ fn test_emit_csv() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(remove_file("./test_emit_csv.csv").is_ok());
|
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<dyn io::Write> =
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,9 +151,9 @@ impl Detection {
|
|||||||
"Medium",
|
"Medium",
|
||||||
"Low",
|
"Low",
|
||||||
"Informational",
|
"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]);
|
let mut levelcounts = Vec::from([0, 0, 0, 0, 0, 0]);
|
||||||
for rule in rules.into_iter() {
|
for rule in rules.into_iter() {
|
||||||
if rule.check_exist_countdata() {
|
if rule.check_exist_countdata() {
|
||||||
|
|||||||
@@ -188,6 +188,11 @@ impl Message {
|
|||||||
return Option::Some(datetime.unwrap());
|
return Option::Some(datetime.unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// message内のマップをクリアする。テストする際の冪等性の担保のため作成。
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.map.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlertMessage {
|
impl AlertMessage {
|
||||||
|
|||||||
Reference in New Issue
Block a user