use std::collections::HashMap;
use rsigma_parser::{
ArrayQuantifier, CorrelationCondition, CorrelationType, FieldAlias, FilterRuleTarget, Level,
LogSource, Quantifier, Related, SelectorPattern, Status, Timespan, WindowMode,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IrRule {
pub metadata: IrRuleMetadata,
pub logsource: LogSource,
pub sigma_version: Option<u32>,
pub detections: HashMap<String, IrDetection>,
pub conditions: Vec<IrCondition>,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct IrRuleMetadata {
pub title: String,
pub id: Option<String>,
pub name: Option<String>,
pub level: Option<Level>,
pub tags: Vec<String>,
pub status: Option<Status>,
pub description: Option<String>,
pub author: Option<String>,
pub date: Option<String>,
pub modified: Option<String>,
pub references: Vec<String>,
pub falsepositives: Vec<String>,
pub fields: Vec<String>,
pub related: Vec<Related>,
pub license: Option<String>,
pub taxonomy: Option<String>,
pub scope: Vec<String>,
pub custom_attributes: HashMap<String, Value>,
pub schema_affinity: Option<Vec<String>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrDetection {
AllOf(Vec<IrDetectionItem>),
AnyOf(Vec<IrDetection>),
Keywords(IrMatcher),
ArrayMatch {
field: String,
quantifier: ArrayQuantifier,
body: Box<IrDetection>,
},
And(Vec<IrDetection>),
Conditional {
named: HashMap<String, IrDetection>,
condition: IrCondition,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IrDetectionItem {
pub field: Option<String>,
pub matcher: IrMatcher,
pub exists: Option<bool>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum IrStrOp {
Exact,
Contains,
StartsWith,
EndsWith,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum IrPatternPart {
Literal(String),
WildcardMulti,
WildcardSingle,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct IrPattern {
pub parts: Vec<IrPatternPart>,
}
impl IrPattern {
pub fn is_plain(&self) -> bool {
self.parts
.iter()
.all(|p| matches!(p, IrPatternPart::Literal(_)))
}
pub fn has_wildcards(&self) -> bool {
!self.is_plain()
}
pub fn as_plain(&self) -> Option<String> {
if !self.is_plain() {
return None;
}
let mut s = String::new();
for p in &self.parts {
if let IrPatternPart::Literal(t) = p {
s.push_str(t);
}
}
Some(s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum IrEncoding {
Wide,
Utf16,
Utf16Be,
Base64,
Base64Offset,
Windash,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrMatcher {
Str {
op: IrStrOp,
pattern: IrPattern,
case_insensitive: bool,
},
Encoded {
encodings: Vec<IrEncoding>,
op: IrStrOp,
value: String,
case_insensitive: bool,
},
Regex {
pattern: String,
case_insensitive: bool,
multiline: bool,
dotall: bool,
cased: bool,
},
Cidr {
network: String,
},
NumericEq(IrNumber),
NumericGt(IrNumber),
NumericGte(IrNumber),
NumericLt(IrNumber),
NumericLte(IrNumber),
Exists(bool),
FieldRef {
field: String,
case_insensitive: bool,
},
Null,
BoolEq(bool),
Expand {
template: Vec<IrExpandPart>,
case_insensitive: bool,
},
TimestampPart {
part: IrTimePart,
inner: Box<IrMatcher>,
},
Not(Box<IrMatcher>),
AnyOf(Vec<IrMatcher>),
AllOf(Vec<IrMatcher>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrExpandPart {
Literal(String),
Placeholder(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum IrTimePart {
Minute,
Hour,
Day,
Week,
Month,
Year,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrNumber {
Literal(f64),
DynamicSourceRef {
source_id: String,
extract: Option<IrExtractExpr>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrExtractExpr {
Jq(String),
JsonPath(String),
Cel(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IrCondition {
Detection(String),
And(Vec<IrCondition>),
Or(Vec<IrCondition>),
Not(Box<IrCondition>),
Selector {
quantifier: Quantifier,
pattern: SelectorPattern,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IrCorrelation {
pub metadata: IrRuleMetadata,
pub sigma_version: Option<u32>,
pub correlation_type: CorrelationType,
pub rules: Vec<String>,
pub group_by: Vec<String>,
pub timespan: Timespan,
pub window: WindowMode,
pub gap: Option<Timespan>,
pub condition: CorrelationCondition,
pub aliases: Vec<FieldAlias>,
pub generate: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IrFilter {
pub metadata: IrRuleMetadata,
pub sigma_version: Option<u32>,
pub rules: FilterRuleTarget,
pub logsource: Option<LogSource>,
pub detections: HashMap<String, IrDetection>,
pub conditions: Vec<IrCondition>,
}