rswappalyzer_engine/core/
pattern.rs1use rustc_hash::FxHashMap;
2use serde::{Deserialize, Serialize};
3use crate::{MatchScope, core::cached_rule::CachedScopeRule};
4
5use super::enums::{MatchCondition, MatchType};
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub struct Pattern {
10 pub pattern: String,
11 pub match_type: MatchType,
12 pub version_template: Option<String>,
13 pub confidence: u8,
14}
15
16#[derive(Debug, Clone, PartialEq)]
18pub struct KeyedPattern {
19 pub key: String, pub pattern: Pattern, }
22
23impl From<(String, Pattern)> for KeyedPattern {
24 fn from((key, pattern): (String, Pattern)) -> Self {
25 KeyedPattern { key, pattern }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Default)]
31pub struct MatchRuleSet {
32 pub condition: MatchCondition, pub list_patterns: Vec<Pattern>, pub keyed_patterns: Vec<KeyedPattern>, }
36
37impl MatchRuleSet {
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn add_list_pattern(&mut self, pattern: Pattern) {
44 self.list_patterns.push(pattern);
45 }
46
47 pub fn add_keyed_pattern(&mut self, keyed_pattern: KeyedPattern) {
49 self.keyed_patterns.push(keyed_pattern);
50 }
51
52 pub fn with_condition(condition: MatchCondition) -> Self {
54 Self {
55 condition,
56 list_patterns: Vec::new(),
57 keyed_patterns: Vec::new(),
58 }
59 }
60
61 pub fn from_cached(scope: &MatchScope, cached: CachedScopeRule) -> Self {
63 let mut rule_set = Self::with_condition(cached.condition);
64 match scope {
65 MatchScope::Url | MatchScope::Html | MatchScope::Script | MatchScope::ScriptSrc => {
66 if let Some(patterns) = cached.list_patterns {
67 rule_set.list_patterns = patterns;
68 }
69 }
70 MatchScope::Header | MatchScope::Cookie | MatchScope::Meta | MatchScope::Js=> {
71 if let Some(keyed) = cached.keyed_patterns {
72 rule_set.keyed_patterns = keyed.into_iter()
74 .flat_map(|(k, v)| v.into_iter().map(move |p| KeyedPattern::from((k.clone(), p))))
75 .collect();
76 }
77 }
78 }
79 rule_set
80 }
81
82 pub fn to_cached(&self, scope: &MatchScope) -> CachedScopeRule {
84 let mut cached = CachedScopeRule {
85 condition: self.condition.clone(),
86 list_patterns: None,
87 keyed_patterns: None,
88 };
89 match scope {
90 MatchScope::Url | MatchScope::Html | MatchScope::Script | MatchScope::ScriptSrc => {
91 if !self.list_patterns.is_empty() {
92 cached.list_patterns = Some(self.list_patterns.clone());
93 }
94 }
95 MatchScope::Header | MatchScope::Cookie | MatchScope::Meta | MatchScope::Js => {
96 if !self.keyed_patterns.is_empty() {
97 let mut keyed: FxHashMap<String, Vec<Pattern>> = FxHashMap::default();
99 for kp in &self.keyed_patterns {
100 keyed.entry(kp.key.clone())
101 .or_default()
102 .push(kp.pattern.clone());
103 }
104 cached.keyed_patterns = Some(keyed);
105 }
106 }
107 }
108 cached
109 }
110}