use super::super::prelude::*;
use crate::ast::group::WplGroupType;
use crate::derive_base_prs;
use crate::eval::runtime::field::FieldEvalUnit;
use crate::eval::value::parse_def::PatternParser;
use crate::eval::value::parser::physical::foundation::gen_chars;
use crate::eval::value::parser::{ParserFactory, protocol};
use crate::parser::error::IntoWplCodeError;
use crate::parser::utils::{quot_r_str, quot_str, take_kv_key, window_path};
use wp_model_core::model::FNameStr;
derive_base_prs!(KeyValP);
impl PatternParser for KeyValP {
fn pattern_parse(
&self,
e_id: u64,
fpu: &FieldEvalUnit,
ups_sep: &WplSep,
data: &mut &str,
_name: FNameStr,
out: &mut Vec<DataField>,
) -> ModalResult<()> {
let _ = multispace0.parse_next(data)?;
let (key, _, _) =
(take_kv_key, multispace0, alt((literal(":"), literal("=")))).parse_next(data)?;
match fpu.group_enum {
WplGroupType::SomeOf(_) => value_take(e_id, fpu, ups_sep, data, key, out),
_ => protocol::take_sub_tdo(e_id, fpu, ups_sep, data, key, out),
}
}
fn patten_gen(
&self,
gnc: &mut GenChannel,
f_conf: &WplField,
g_conf: Option<&FieldGenConf>,
) -> WplCodeResult<DataField> {
let key = gen_chars(gnc, 3, false);
if let Some(conf) = g_conf {
let meta = DataType::from(&conf.gen_type).map_err(|e| e.into_wpl_err())?;
let parser = ParserFactory::create(&meta)?;
let sep = f_conf.resolve_sep(&WplSep::default());
let field = parser.generate(gnc, &sep, f_conf, Some(conf))?;
return Ok(field.data_field);
}
let val = gen_chars(gnc, 30, false);
Ok(DataField::from_chars(key, val))
}
}
fn value_take(
e_id: u64,
fpu: &FieldEvalUnit,
upper_sep: &WplSep,
data: &mut &str,
key: &str,
out: &mut Vec<DataField>,
) -> ModalResult<()> {
multispace0.parse_next(data)?;
let has_sub = fpu.get_sub_fpu(key).is_some();
let mut p_sep = fpu.conf().resolve_sep(upper_sep);
p_sep.apply_default(WplSep::inherited_sep("\\0"));
let str_val_r = alt((quot_r_str, quot_str, window_path)).parse_next(data);
if has_sub {
if let Some(sub_fpu) = fpu.get_sub_fpu(key) {
match str_val_r {
Ok(mut str_val) => {
let run_key = sub_fpu.conf().run_key(key);
let sep = fpu.conf().resolve_sep(&p_sep);
return sub_fpu.parse(e_id, &sep, &mut str_val, run_key, out);
}
Err(_) => {
let sep = fpu.conf().resolve_sep(&p_sep);
let run_key = sub_fpu.conf().run_key(key);
return sub_fpu.parse(e_id, &sep, data, run_key, out);
}
}
}
} else {
match str_val_r {
Ok(str_val) => {
out.push(DataField::from_chars(key, str_val));
return Ok(());
}
Err(_) => {
let sep = p_sep; let val = sep.read_until_sep(data)?;
let trim_val = val.trim();
out.push(DataField::from_chars(key, trim_val));
return Ok(());
}
}
}
fail.context(ctx_desc("not found sub fpu "))
.parse_next(data)
}
#[cfg(test)]
#[allow(clippy::useless_vec)]
mod tests {
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use wp_model_core::raw::RawData;
use crate::ast::WplField;
use crate::eval::runtime::vm_unit::WplEvaluator;
use crate::eval::value::test_utils::ParserTUnit;
use crate::parser::error::WplCodeResult;
use orion_error::dev::testing::TestAssert;
use wp_model_core::model::DataRecord;
use super::*;
#[test]
fn test_key_name() -> WplCodeResult<()> {
let mut data = r#"destination-zone="tr\"ust""#;
let conf = WplField::try_parse(r#"kv(@destination-zone)"#).assert();
let field = ParserTUnit::from_auto(conf).verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(
field[0],
DataField::from_chars("destination-zone".to_string(), r#"tr\"ust"#)
);
let mut data = r#"time="2023-05-15 09:22:44" "#;
let conf = WplField::try_parse(r#"kv(time@time\")"#).assert();
let field =
ParserTUnit::from_auto(conf).verify_parse_suc_end_meta(&mut data, DataType::Time);
assert_eq!(
field,
vec![DataField::from_time("time".to_string(), {
let d = NaiveDate::from_ymd_opt(2023, 5, 15).assert();
let t = NaiveTime::from_hms_milli_opt(9, 22, 44, 0).unwrap();
NaiveDateTime::new(d, t)
}),]
);
let mut data = r#"protocal(80)="tcp""#;
let conf = WplField::try_parse(r#"kv(@protocal(80))"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_end_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars(
"protocal(80)".to_string(),
"tcp".to_string()
)]
);
Ok(())
}
#[test]
fn test_key_2() -> WplCodeResult<()> {
let mut data = "sys_name : 幻云 , msg_type:attack_log";
let conf = WplField::try_parse(r#"kv(@sys_name)\,"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars(
"sys_name".to_string(),
"幻云".to_string()
),]
);
Ok(())
}
#[test]
fn test_key_3() -> WplCodeResult<()> {
let conf = WplField::try_parse(r#"kv(@time)"#).assert();
let mut data = r#"time="2023-05-15 09:22:44" "#;
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_end_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars(
"time".to_string(),
"2023-05-15 09:22:44".to_string()
),]
);
Ok(())
}
#[test]
fn test_key_4() -> WplCodeResult<()> {
let mut data = r#" pid:666, asid:100028"#;
let conf = WplField::try_parse(r#"kv(@pid)\,,kv(@asid)\,"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars("pid".to_string(), "666".to_string()),]
);
Ok(())
}
#[test]
fn test_kv_arr1() -> WplCodeResult<()> {
let data = r#"dip=["1.1.1.1","2.2.2.2"]"#;
let rule = r#" rule x { (kv(array/chars@dip))}"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
Ok(())
}
#[test]
fn test_kv_arr2() -> WplCodeResult<()> {
let data = r#"dip=[1.1.1.1,2.2.2.2]"#;
let rule = r#" rule x { (kv(array/ip@dip))}"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
Ok(())
}
#[test]
fn test_kv_arr3() -> WplCodeResult<()> {
let data = r#"dip=[]"#;
let rule = r#" rule x { (kv(array/ip@dip))}"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
assert!(tdc.field("dip").is_some());
let rule = r#" rule x { (kv(array/ip@dip))}"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
assert!(tdc.field("dip").is_some());
Ok(())
}
#[test]
fn test_kv_arr4() -> WplCodeResult<()> {
let data = r#"d=["1","1"]|e=["2","2"]|a= []|b=["3","3"]"#;
let rule = r#" rule x { some_of(kv(array/chars))\| }"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
Ok(())
}
#[test]
fn test_key_point() -> WplCodeResult<()> {
let mut data =
r#"detail.sha256="2e7d8e43f518d2f2e54676069510bf48aa2289ca19c0f4165a1b6d4c18351ac9""#;
let conf = WplField::try_parse(r#"kv"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars(
"detail.sha256".to_string(),
"2e7d8e43f518d2f2e54676069510bf48aa2289ca19c0f4165a1b6d4c18351ac9".to_string()
),]
);
let mut data =
r#"detail.sha256="2e7d8e43f518d2f2e54676069510bf48aa2289ca19c0f4165a1b6d4c18351ac9""#;
let conf = WplField::try_parse(r#"kv(@detail.sha256)"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(
field,
vec![DataField::from_chars(
"detail.sha256".to_string(),
"2e7d8e43f518d2f2e54676069510bf48aa2289ca19c0f4165a1b6d4c18351ac9".to_string()
),]
);
Ok(())
}
#[test]
fn test_key_diy_sep() -> WplCodeResult<()> {
let data = r#"x.a="hello"!|x.b="18"!|x.c=20"#;
let rule = r#" rule x { (kv(chars@x.a:y.a),kv(chars@x.b),kv(digit@x.c))\!\|} "#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
let expected = vec![
DataField::from_chars("y.a".to_string(), "hello".to_string()),
DataField::from_chars("x.b".to_string(), "18".to_string()),
DataField::from_digit("x.c".to_string(), 20),
];
assert_eq!(
tdc.items.iter().map(|s| s.as_field()).collect::<Vec<_>>(),
expected.iter().collect::<Vec<_>>()
);
Ok(())
}
#[test]
fn test_kv_chars2() -> WplCodeResult<()> {
let rule = r#" rule x {(chars:content), some_of( kv(chars<",">@event_content) ) } "#;
let data = r#""主机172.16.12.20存在可疑进程参数问题,进程fscan_amd64的启动参数为./fscan_amd64 -h 172.16.12.0/24,符合可疑进程参数的特性。" event_content="主机172.16.12.20存在可疑进程参数问题,进程fscan_amd64的启动参数为./fscan_amd64 -h 172.16.12.0/24,符合可疑进程参数的特性。"
"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
assert_eq!(
tdc.get_field_owned("content"),
Some(DataField::from_chars(
"content",
r#"主机172.16.12.20存在可疑进程参数问题,进程fscan_amd64的启动参数为./fscan_amd64 -h 172.16.12.0/24,符合可疑进程参数的特性。"#
))
);
assert_eq!(
tdc.get_field_owned("event_content"),
Some(DataField::from_chars(
"event_content",
r#"主机172.16.12.20存在可疑进程参数问题,进程fscan_amd64的启动参数为./fscan_amd64 -h 172.16.12.0/24,符合可疑进程参数的特性。"#
))
);
Ok(())
}
#[test]
fn test_kv_chars1() -> WplCodeResult<()> {
let rule = r#" rule x {(chars:a\\\s), some_of( kv(chars@b), ), (json()) } "#;
let data = r#"sddD:\招标项目\6-MSS\mss日志映射表 b="sddD:\招标项目\6-MSS\mss日志映射表" {"c":"sddD:\\招标项目\\6-MSS\\mss日志映射表"}"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
println!("{}", tdc);
assert_eq!(
tdc.get_field_owned("b"),
Some(DataField::from_chars(
"b",
r#"sddD:\招标项目\6-MSS\mss日志映射表"#
))
);
assert_eq!(
tdc.get_field_owned("c"),
Some(DataField::from_chars(
"c",
r#"sddD:\\招标项目\\6-MSS\\mss日志映射表"#
))
);
Ok(())
}
#[test]
fn test_kv_runtime_key_with_parentheses() -> WplCodeResult<()> {
let rule = r#"rule test { (kv(@protocal(80))) }"#;
let data = r#"protocal(80)=tcp"#;
let pipe = WplEvaluator::from_code(rule)?;
let (record, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
assert_eq!(
record.field("protocal(80)").map(|s| s.as_field()),
Some(&DataField::from_chars("protocal(80)", "tcp"))
);
Ok(())
}
#[test]
fn test_kv_runtime_keys_with_brackets_angles_braces() -> WplCodeResult<()> {
let rule = r#"rule test { (kv,kv,kv)\s }"#;
let data = r#"arr[0]=true list<int>=100 set{a}=value"#;
let pipe = WplEvaluator::from_code(rule)?;
let (record, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
assert_eq!(
record.field("arr[0]").map(|s| s.as_field()),
Some(&DataField::from_chars("arr[0]", "true"))
);
assert_eq!(
record.field("list<int>").map(|s| s.as_field()),
Some(&DataField::from_chars("list<int>", "100"))
);
assert_eq!(
record.field("set{a}").map(|s| s.as_field()),
Some(&DataField::from_chars("set{a}", "value"))
);
Ok(())
}
#[test]
fn test_kv_multi_keys() -> WplCodeResult<()> {
let rule = r#" rule x { (kv,kv(digit),kv(digit@x.c, digit@x.c1:x.c))\!\|} "#;
let data = r#"x.a="hello"!|x.b=18!|x.c=20"#;
let pipe = WplEvaluator::from_code(rule)?;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
asert_kv_x_obj(tdc);
let data = r#"x.a="hello"!|x.b=18!|x.c1=20"#;
let (tdc, _) = pipe
.proc(0, RawData::from_string(data.to_string()), 0)
.map_err(|e| e.into_wpl_err())?;
asert_kv_x_obj(tdc);
Ok(())
}
fn asert_kv_x_obj(tdc: DataRecord) {
let expected = vec![
DataField::from_chars("x.a".to_string(), "hello".to_string()),
DataField::from_digit("x.b", 18),
DataField::from_digit("x.c".to_string(), 20),
];
assert_eq!(
tdc.items.iter().map(|s| s.as_field()).collect::<Vec<_>>(),
expected.iter().collect::<Vec<_>>()
);
}
#[test]
fn test_kv_bracket_key() -> WplCodeResult<()> {
let mut data = r#"fn(arg)="hello""#;
let conf = WplField::try_parse(r#"kv"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(field[0], DataField::from_chars("fn(arg)", "hello"));
let mut data = r#"list<int>=100"#;
let conf = WplField::try_parse(r#"kv"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(field[0], DataField::from_chars("list<int>", "100"));
let mut data = r#"set{a}:value"#;
let conf = WplField::try_parse(r#"kv"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(field[0], DataField::from_chars("set{a}", "value"));
let mut data = r#"arr[0]=ok"#;
let conf = WplField::try_parse(r#"kv"#).assert();
let field = ParserTUnit::new(KeyValP::default(), conf)
.verify_parse_suc_meta(&mut data, DataType::Chars);
assert_eq!(field[0], DataField::from_chars("arr[0]", "ok"));
Ok(())
}
}