Skip to content

Commit

Permalink
feat: i18n and login
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Nov 8, 2023
1 parent 4832e11 commit 8089e51
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 3 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,5 @@ pub enum WebProxyRuleCategory {
- [x] SIGMA rules support.
- [x] Enforced storage schema for logs. Each source extracts multiple fields with different names. In elastic its not recomended to have more than 1000 fields. Also, it must allow renaming of fields because ECS uses dots in the field names but the majority of databases cant.
- [ ] GDPR included for logs: An analyst does not need to know information about users, such as the websites they visit or the emails they receive. Integrated into the Storage Schema, like the url related fields must be stored encrypted for WebProxy events or the email.subject, email.files or email.source.user.name for Mail events.
- [ ] Mantaince calendar. Used to disable alerting of events related to device configurations, like FortiSIEM does.
- [ ] Mantaince calendar. Used to disable alerting of events related to device configurations, like FortiSIEM does.
- [x] Internacionalization of texts
9 changes: 8 additions & 1 deletion src/components/command_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,14 @@ pub struct UseCaseDefinition {
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LoginUser {
#[non_exhaustive]
pub enum LoginUser {
Password(LoginUserPass),
ApiKey(String)
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LoginUserPass {
pub username: String,
pub password: String,
}
Expand Down
196 changes: 196 additions & 0 deletions src/components/dataset/i18n.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
use crate::prelude::types::LogString;
use crossbeam_channel::Sender;
use serde::{Serialize, Deserialize};
use std::collections::BTreeMap;
use std::sync::Arc;

#[derive(Serialize, Debug)]
pub enum UpdateI18n {
Add((LogString, LogString)),
Remove(LogString),
Replace(I18nDataset),
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialOrd, PartialEq, Ord, Eq)]
pub enum Language {
ES,
#[default]
EN,
FR,
Other(&'static str)
}
impl Copy for Language {

}

#[derive(Debug, Clone)]
pub struct I18nSynDataset {
dataset: Arc<I18nDataset>,
comm: Sender<UpdateI18n>,
}
impl I18nSynDataset {
pub fn new(dataset: Arc<I18nDataset>, comm: Sender<UpdateI18n>) -> I18nSynDataset {
return I18nSynDataset { dataset, comm };
}
pub fn empty() -> Self {
let (sender, _) = crossbeam_channel::bounded(1);

return Self { dataset : Arc::new(I18nDataset::new()), comm : sender };
}
pub fn insert<S>(&self, key: S, data: S)
where
S: Into<LogString>,
{
match self
.comm
.try_send(UpdateI18n::Add((key.into(), data.into())))
{
Ok(_) => {}
Err(_) => {}
};
}
pub fn remove<S>(&self, key: S)
where
S: Into<LogString>,
{
// Todo: improve with local cache to send retries
match self.comm.try_send(UpdateI18n::Remove(key.into())) {
Ok(_) => {}
Err(_) => {}
};
}
pub fn update(&self, data: I18nDataset) {
// Todo: improve with local cache to send retries
match self.comm.try_send(UpdateI18n::Replace(data)) {
Ok(_) => {}
Err(_) => {}
};
}
pub fn get(&self, text: &LogString, language : &Language) -> Option<&LogString> {
// Todo improve with cached content
self.dataset.get(text, language)
}
/// Obtains a text from the language library
///
/// ```rust
/// use usiem::prelude::i18n::*;
/// use usiem::prelude::types::LogString;
/// let mut dataset = I18nDataset::new();
/// dataset.insert(
/// Language::ES,
/// LogString::Borrowed("LocalIp"),
/// LogString::Borrowed("IP Local"),
/// );
/// dataset.insert(
/// Language::EN,
/// LogString::Borrowed("LocalIp"),
/// LogString::Borrowed("Local IP"),
/// );
/// assert_eq!(
/// dataset.get_or_default("LocalIp", &Language::ES),
/// Some(&LogString::Borrowed("IP Local"))
/// );
/// assert_eq!(
/// dataset.get_or_default("LocalIp", &Language::FR),
/// Some(&LogString::Borrowed("Local IP"))
/// );
/// ```
pub fn get_or_default(&self, text: &str, language : &Language) -> Option<&LogString> {
self.dataset.get_or_default(text, language)
}
}
#[derive(Serialize, Debug)]
pub struct I18nDataset {
/// Language -> Text -> Value
data: BTreeMap<LogString, BTreeMap<Language, LogString>>,
}

impl I18nDataset {
pub fn new() -> I18nDataset {
return I18nDataset {
data: BTreeMap::new(),
};
}
pub fn set_dictionary<M>(&mut self, language: Language, data: M)
where
M: Into<BTreeMap<LogString, LogString>>,
{
let new_data : BTreeMap<LogString, LogString> = data.into();
for (k, value) in new_data {
if self.data.contains_key(&k) {
let map = match self.data.get_mut(&k) {
Some(v) => v,
None => return
};
map.insert(language, value);
}else {
let mut map = BTreeMap::new();
map.insert(language, value);
self.data.insert(k, map);
}
}
}
pub fn insert(&mut self, language: Language, text: LogString, value : LogString){
if self.data.contains_key(&text) {
let map = match self.data.get_mut(&text) {
Some(v) => v,
None => return
};
map.insert(language, value);
}else {
let mut map = BTreeMap::new();
map.insert(language, value);
self.data.insert(text, map);
}
}
pub fn get(&self, text: &str, language : &Language) -> Option<&LogString> {
self.data.get(text)?.get(language)
}
pub fn get_or_default(&self, text: &str, language : &Language) -> Option<&LogString> {
let langs = self.data.get(text)?;

match langs.get(language){
Some(lang) => Some(lang),
None => {
match langs.get(&Language::EN) {
Some(lang) => Some(lang),
None => {
// Return first to be found
Some(langs.first_key_value()?.1)
}
}
}
}
}
pub fn internal_ref(&self) -> &BTreeMap<LogString, BTreeMap<Language, LogString>> {
&self.data
}
}

#[cfg(test)]
mod tests {

use super::*;
#[test]
fn should_find_data_in_map() {
let mut dataset = I18nDataset::new();
dataset.insert(
Language::ES,
LogString::Borrowed("LocalIp"),
LogString::Borrowed("IP Local"),
);
dataset.insert(
Language::EN,
LogString::Borrowed("LocalIp"),
LogString::Borrowed("Local IP"),
);
assert_eq!(
dataset.get_or_default("LocalIp", &Language::ES),
Some(&LogString::Borrowed("IP Local"))
);
assert_eq!(
dataset.get_or_default("LocalIp", &Language::FR),
Some(&LogString::Borrowed("Local IP"))
);
}
}
11 changes: 10 additions & 1 deletion src/components/dataset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod rules;
pub mod text_map;
pub mod text_map_list;
pub mod text_set;
pub mod i18n;

use crate::prelude::types::LogString;
use calendar::{CalendarSynDataset, UpdateCalendar};
Expand All @@ -25,6 +26,7 @@ use std::fmt;
use text_map::{TextMapSynDataset, UpdateTextMap};
use text_map_list::{TextMapListSynDataset, UpdateTextMapList};
use text_set::{TextSetSynDataset, UpdateTextSet};
use i18n::{UpdateI18n, I18nSynDataset};

/// Commonly used datasets. They are filled with the information extracted form logs, from the CMDB, from user commands or from repetitive Task like GeoIP.
/// Dataset are used, but not exclusivally, in the enrichment phase.
Expand Down Expand Up @@ -84,6 +86,8 @@ pub enum SiemDataset {
MantainceCalendar(CalendarSynDataset),
/// Configuration of components. Allows modifications of component parameters in real time.
Configuration(TextMapSynDataset),
/// Internacionalization of SIEM texts
I18n(I18nSynDataset),
/// Secret store. A component will only be able to access his own secrets.
Secrets((LogString, TextMapSynDataset)),
}
Expand Down Expand Up @@ -661,6 +665,8 @@ pub enum SiemDatasetType {
MantainceCalendar,
Configuration,
Secrets(LogString),
/// Internacionalization
I18n
}

impl SiemDataset {
Expand Down Expand Up @@ -693,7 +699,8 @@ impl SiemDataset {
SiemDataset::CustomTextList((name, _)) => SiemDatasetType::CustomTextList(name.clone()),
SiemDataset::CustomMapTextList((name, _)) => {
SiemDatasetType::CustomMapTextList(name.clone())
}
},
SiemDataset::I18n(_) => SiemDatasetType::I18n,
SiemDataset::Secrets((name, _)) => SiemDatasetType::Secrets(name.clone()),
}
}
Expand Down Expand Up @@ -750,6 +757,7 @@ impl Serialize for SiemDataset {
SiemDataset::MantainceCalendar(_) => "MantainceCalendar",
SiemDataset::Configuration(_) => "Configuration",
SiemDataset::HostVulnerable(_) => "HostVulnerable",
SiemDataset::I18n(_) => "I18n",
SiemDataset::CustomMapIpNet((name, _)) => {
state.serialize_field("name", name)?;
"CustomMapIpNet"
Expand Down Expand Up @@ -812,4 +820,5 @@ pub enum UpdateDataset {
Secrets(UpdateTextMap),
HostVulnerable(UpdateTextMapList),
CorrelationRules(UpdateGeoIp),
I18n(UpdateI18n)
}

0 comments on commit 8089e51

Please sign in to comment.