stalkerware_indicators/
lib.rs1pub mod errors;
23mod structs;
24
25use crate::errors::*;
26pub use crate::structs::*;
27use std::fmt;
28use std::fs;
29use std::path::Path;
30
31pub fn parse_from_buf(buf: &[u8]) -> Result<Vec<Rule>> {
33 let data =
34 serde_yaml::from_slice(buf).context("Failed to parse stalkerware-indicators rules")?;
35 Ok(data)
36}
37
38pub fn parse_from_file<T: AsRef<Path> + fmt::Debug>(path: T) -> Result<Vec<Rule>> {
40 let buf = fs::read(&path).with_context(|| anyhow!("Failed to read file: {:?}", path))?;
41 parse_from_buf(&buf)
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn test_load_2022_09_14() {
50 let rules = parse_from_file("test_data/ioc-2022-09-14.yaml").unwrap();
51 assert_eq!(rules.len(), 117);
52 }
53
54 #[test]
55 fn test_load_2022_12_15() {
56 let rules = parse_from_file("test_data/ioc-2022-12-15.yaml").unwrap();
57 assert_eq!(rules.len(), 146);
58 }
59
60 #[test]
61 fn parse_minimal() {
62 let buf = r#"
63- name: Minimal
64 type: stalkerware
65 "#;
66
67 let rules = parse_from_buf(buf.as_bytes()).unwrap();
68 assert_eq!(
69 rules,
70 vec![Rule {
71 name: "Minimal".to_string(),
72 names: Vec::new(),
73 r#type: "stalkerware".to_string(),
74 packages: Vec::new(),
75 distribution: Vec::new(),
76 certificates: Vec::new(),
77 websites: Vec::new(),
78 c2: C2Rule {
79 ips: Vec::new(),
80 domains: Vec::new(),
81 },
82 },]
83 );
84 }
85
86 #[test]
87 fn parse_empty_c2() {
88 let buf = r#"
89- name: Minimal
90 type: stalkerware
91 c2: {}
92 "#;
93
94 let rules = parse_from_buf(buf.as_bytes()).unwrap();
95 assert_eq!(
96 rules,
97 vec![Rule {
98 name: "Minimal".to_string(),
99 names: Vec::new(),
100 r#type: "stalkerware".to_string(),
101 packages: Vec::new(),
102 distribution: Vec::new(),
103 certificates: Vec::new(),
104 websites: Vec::new(),
105 c2: C2Rule {
106 ips: Vec::new(),
107 domains: Vec::new(),
108 },
109 },]
110 );
111 }
112}