1use serde::Serialize;
2use std::collections::{BTreeMap, BTreeSet};
3
4use super::SiemLog;
5
6#[path = "base_schema.rs"]
7pub mod base_schema;
8
9#[derive(Serialize, Debug, Clone)]
11pub struct FieldSchema {
12 pub fields: BTreeMap<&'static str, FieldType>,
13 pub allow_unknown_fields: bool,
15 pub gdpr: Option<GdprProtection>,
17}
18
19impl Default for FieldSchema {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl FieldSchema {
26 pub fn new() -> FieldSchema {
27 let mut basic_fields = BTreeMap::new();
28 basic_fields.insert(
29 "origin",
30 FieldType::Ip("IP or Hostname of the server that sent the log"),
31 );
32 basic_fields.insert(
33 "tenant",
34 FieldType::Text("Customer name for SOC environments. Ex: Contoso"),
35 );
36 basic_fields.insert(
37 "product",
38 FieldType::Text("Name of the product for wich the log belongs. Ex: ASA"),
39 );
40 basic_fields.insert("service", FieldType::Text("Subset of the product logs. Like a OS that can have multiple programs running inside generating multiple logs."));
41 basic_fields.insert(
42 "category",
43 FieldType::Text("Category of the device: Firewall, web, antivirus"),
44 );
45 basic_fields.insert(
46 "vendor",
47 FieldType::Text("Company that created the product. Ex: Cisco"),
48 );
49 basic_fields.insert("event.type", FieldType::Text("uSIEM log type: SiemEvent"));
50 basic_fields.insert("tags", FieldType::Text("Tags to better describe the event"));
51 basic_fields.insert(
52 "message",
53 FieldType::Text("Original log message including syslog header"),
54 );
55 basic_fields.insert(
56 "event_received",
57 FieldType::Date("Timestamp at witch the log arrived "),
58 );
59 basic_fields.insert(
60 "event_created",
61 FieldType::Date("Timestamp at witch the log was generated"),
62 );
63 FieldSchema {
64 fields: basic_fields,
65 allow_unknown_fields: false,
66 gdpr: None,
67 }
68 }
69 pub fn add_schema(&mut self, schema: &FieldSchema) {
70 for (name, element) in &schema.fields {
71 match element {
72 FieldType::TextOptions(list_val, _doc) => match self.fields.get_mut(name) {
73 Some(FieldType::TextOptions(alredy_val, _doc2)) => {
74 for (vl_1, vl_2) in list_val {
75 alredy_val.insert(vl_1, vl_2);
76 }
77 }
78 _ => {
79 self.fields.insert(name, element.clone());
80 }
81 },
82 _ => {
83 self.fields.insert(name, element.clone());
84 }
85 }
86 }
87 }
88 pub fn insert(&mut self, key: &'static str, value: FieldType) -> Option<FieldType> {
89 self.fields.insert(key, value)
90 }
91 pub fn set_gdpr(&mut self, protection: Option<GdprProtection>) {
92 self.gdpr = protection;
93 }
94 pub fn protected_field(&self, field: &str) -> bool {
95 match &self.gdpr {
96 Some(val) => val.fields.contains(field),
97 None => false,
98 }
99 }
100 pub fn get_field(&self, field: &str) -> Option<&FieldType> {
101 self.fields.get(field)
102 }
103 pub fn field_names(&self) -> Vec<String> {
104 let mut to_ret = Vec::with_capacity(self.fields.len());
105 for key in self.fields.keys() {
106 to_ret.push(key.to_string());
107 }
108 to_ret
109 }
110 pub fn remove_fields(&mut self, fields: &BTreeSet<&'static str>) {
112 for key in fields.iter() {
113 self.fields.remove(*key);
114 }
115 }
116
117 pub fn apply(&self, log: &mut SiemLog) {
119 log.fields.retain(|k, _v| self.fields.contains_key(&k[..]));
120 }
121}
122
123#[derive(Serialize, Debug, Clone)]
124pub enum FieldType {
125 Ip(&'static str),
127 Array(&'static str),
128 Text(&'static str),
130 Numeric(&'static str),
132 Decimal(&'static str),
134 Date(&'static str),
136 TextOptions(BTreeMap<&'static str, &'static str>, &'static str),
138}
139
140#[derive(Serialize, Debug, Clone)]
141pub struct GdprProtection {
142 pub fields: BTreeSet<&'static str>,
144 pub method: GdprProtectionMethod,
145}
146
147#[derive(Serialize, Debug, Clone)]
148pub enum GdprProtectionMethod {
149 Storage,
151 ApiProtected,
153}