pub mod messages;
pub mod result;
use kameo::{mailbox::unbounded::UnboundedMailbox, Actor};
use yara_x::Rules;
#[derive(Default)]
pub struct YaraEngine {
rules: Vec<String>,
compiled: Option<Rules>,
}
impl Actor for YaraEngine {
type Mailbox = UnboundedMailbox<Self>;
fn name() -> &'static str {
"scan_engine__yara_x"
}
}
#[cfg(test)]
mod tests {
use super::*;
use kameo::actor::ActorRef;
use messages::{AddRule, CompileRules, ScanBytes};
use result::MatchedRule;
use std::collections::HashMap;
const HELLOWORLD_RULE: &str = r#"
rule HelloWorld {
meta:
description = "Detects `Hello World`"
author = "ctx400"
strings:
$a = "Hello World"
condition:
all of them
}
"#;
const INVALID_RULE_SYNTAX: &str = r#"
rule SyntaxError {
meta:
description = "Should trigger a compilation error"
author = "ctx400"
strings:
$a: "Hello World"
condition:
all of them
}
"#;
const MATCHING_DATA: &[u8] = b"alksdjfhlkjashdflkjh-Hello World-laksjdfhlkjhadsf";
const NONMATCHING_DATA: &[u8] = b"alksdjfhlkajsdhfl-Goodbye World-dfhlkajsdhflkj";
#[tokio::test]
async fn should_match_helloworld_rule() {
let engine_ref: ActorRef<YaraEngine> = kameo::spawn(YaraEngine::default());
engine_ref
.tell(AddRule(HELLOWORLD_RULE.to_string()))
.await
.unwrap();
engine_ref.ask(CompileRules).await.unwrap();
let results: Vec<MatchedRule> = engine_ref
.ask(ScanBytes(MATCHING_DATA.to_vec()))
.await
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(&results.first().unwrap().identifier, "HelloWorld");
let metadata: &HashMap<String, String> = &results.first().unwrap().metadata;
assert_eq!(metadata.get("author").unwrap(), "ctx400");
}
#[tokio::test]
async fn should_not_match_helloworld_rule() {
let engine_ref: ActorRef<YaraEngine> = kameo::spawn(YaraEngine::default());
engine_ref
.tell(AddRule(HELLOWORLD_RULE.to_string()))
.await
.unwrap();
engine_ref.ask(CompileRules).await.unwrap();
let results: Vec<MatchedRule> = engine_ref
.ask(ScanBytes(NONMATCHING_DATA.to_vec()))
.await
.unwrap();
assert_eq!(results.len(), 0);
}
#[tokio::test]
#[should_panic]
async fn should_fail_compile_syntax() {
let engine_ref: ActorRef<YaraEngine> = kameo::spawn(YaraEngine::default());
engine_ref
.tell(AddRule(INVALID_RULE_SYNTAX.to_string()))
.await
.unwrap();
engine_ref.ask(CompileRules).await.unwrap();
}
#[tokio::test]
#[should_panic]
async fn should_fail_no_compiled_rules() {
let engine_ref: ActorRef<YaraEngine> = kameo::spawn(YaraEngine::default());
engine_ref
.ask(ScanBytes(MATCHING_DATA.to_vec()))
.await
.unwrap();
}
}