Skip to content

Commit

Permalink
filtering works
Browse files Browse the repository at this point in the history
  • Loading branch information
janstarke committed May 10, 2024
1 parent b84f91b commit 4e6a08d
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 13 deletions.
26 changes: 25 additions & 1 deletion src/bin/evtxview/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use ratatui::{
};

const INFO_TEXT: &str =
"(Esc) quit | (↑) move up | (↓) move down | (→) next color | (←) previous color";
r#"(Esc) quit | (↑) move up | (↓) move down | (→) next color | (←) previous color |
(x) eXclude by event id" | (i) Include by event id | (R) Reset filter"#;

pub struct App {
evtx_table: EvtxTable,
Expand Down Expand Up @@ -145,13 +146,36 @@ impl App {
KeyCode::Up => self.previous(1),
KeyCode::PageDown => self.next((self.table_view_port.height / 2).into()),
KeyCode::PageUp => self.previous((self.table_view_port.height / 2).into()),
KeyCode::Char('x') => self.exclude_event_id(),
KeyCode::Char('i') => self.include_event_id(),
KeyCode::Char('R') => self.reset_filter(),
_ => {}
}
}
fn exit(&mut self) {
self.exit = true;
}

fn exclude_event_id(&mut self) {
if !self.evtx_table.is_empty() {
if let Some(i) = self.state.selected() {
self.evtx_table.exclude_event_id(i)
}
}
}

fn include_event_id(&mut self) {
if !self.evtx_table.is_empty() {
if let Some(i) = self.state.selected() {
self.evtx_table.include_event_id(i)
}
}
}

fn reset_filter(&mut self) {
self.evtx_table.reset_filter();
}

fn set_selected(&mut self, idx: usize) {
self.state.select(Some(idx));
self.table_scroll_state = self.table_scroll_state.position(idx);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/evtxview/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct Event {
#[allow(unused,non_snake_case)]
pub struct System {
//provider: Provider,
EventID: String,
EventID: u32,
version: String,
level: EventLevel,
task: String,
Expand Down
84 changes: 73 additions & 11 deletions src/bin/evtxview/tui/evtx_table.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::{fs::File, path::Path};

use chrono::{DateTime, Utc};
Expand All @@ -6,7 +7,7 @@ use evtx::{EvtxParser, SerializedEvtxRecord};
use ouroboros::self_referencing;
use quick_xml::de::from_str;
use ratatui::layout::Constraint;
use ratatui::style::Stylize;
use ratatui::style::{Color, Stylize};
use ratatui::widgets::HighlightSpacing;
use ratatui::{
style::{Modifier, Style},
Expand All @@ -18,11 +19,28 @@ use crate::event::Event;

use super::color_scheme::{ColorScheme, PALETTES};

#[derive(Eq, PartialEq, Hash)]
pub enum EventFilter {
ExcludeByEventId(u32),
IncludeByEventId(u32),
}

impl EventFilter {
pub fn filter(&self, rc: &RowContents) -> bool {
match self {
EventFilter::ExcludeByEventId(event_id) => rc.event.system().EventID() != event_id,
EventFilter::IncludeByEventId(event_id) => rc.event.system().EventID() == event_id,
}
}
}

pub struct EvtxTable {
rows: Vec<RowContents>,
sparkline_data: Vec<u64>,
colors: ColorScheme,
timestamp_width: u16,
event_filters: HashSet<EventFilter>,
filtered_rows_count: usize,
}

impl TryFrom<&Path> for EvtxTable {
Expand All @@ -42,8 +60,11 @@ impl TryFrom<&Path> for EvtxTable {
first_ts /= step_size;

for row in rows.iter() {
let ts = usize::try_from((row.record_timestamp.timestamp() / step_size) - first_ts)?;
while ts + 1 > sparkline_data.len() {sparkline_data.push(0)}
let ts =
usize::try_from((row.record_timestamp.timestamp() / step_size) - first_ts)?;
while ts + 1 > sparkline_data.len() {
sparkline_data.push(0)
}
sparkline_data[ts] += 1;
}
}
Expand All @@ -53,11 +74,14 @@ impl TryFrom<&Path> for EvtxTable {
.to_string()
.len(),
)?;
let filtered_rows_count = rows.len();
Ok(EvtxTable {
rows,
colors: ColorScheme::new(&PALETTES[0]),
timestamp_width,
sparkline_data
sparkline_data,
event_filters: HashSet::new(),
filtered_rows_count,
})
}
}
Expand All @@ -82,10 +106,12 @@ impl EvtxTable {

let bar = " █ ";

let rows: Vec<_> = self.filtered_rows().collect();

let table = Table::new(
&self.rows,
rows,
vec![
Constraint::Length(4),
Constraint::Length(2),
Constraint::Length(self.timestamp_width),
Constraint::Length(column_headers[1].len() as u16),
Constraint::Length(column_headers[1].len() as u16),
Expand All @@ -107,12 +133,23 @@ impl EvtxTable {
table
}

fn filtered_rows(&self) -> impl Iterator<Item = &RowContents> {
self.rows.iter().filter(|rc| self.filter_row(rc))
}

fn filter_row(&self, rc: &RowContents) -> bool {
self.event_filters
.iter()
.map(|filter| filter.filter(rc))
.fold(true, |a, b| a & b)
}

pub fn len(&self) -> usize {
self.rows.len()
self.filtered_rows_count
}

pub fn is_empty(&self) -> bool {
self.rows.is_empty()
self.filtered_rows_count == 0
}

pub fn content(&self, idx: usize) -> Option<&String> {
Expand All @@ -122,6 +159,31 @@ impl EvtxTable {
pub fn sparkline_data(&self) -> &Vec<u64> {
&self.sparkline_data
}

pub fn event_id_in_row(&self, filtered_row_id: usize) -> Option<u32> {
self.filtered_rows()
.nth(filtered_row_id)
.map(|r| *r.event.system().EventID())
}

pub fn exclude_event_id(&mut self, filtered_row_id: usize) {
if let Some(event_id) = self.event_id_in_row(filtered_row_id) {
self.event_filters
.insert(EventFilter::ExcludeByEventId(event_id));
}
self.filtered_rows_count = self.filtered_rows().count();
}
pub fn include_event_id(&mut self, filtered_row_id: usize) {
if let Some(event_id) = self.event_id_in_row(filtered_row_id) {
self.event_filters
.insert(EventFilter::IncludeByEventId(event_id));
}
self.filtered_rows_count = self.filtered_rows().count();
}
pub fn reset_filter(&mut self) {
self.event_filters.clear();
self.filtered_rows_count = self.filtered_rows().count();
}
}

#[self_referencing]
Expand Down Expand Up @@ -218,7 +280,7 @@ impl<'r> TryFrom<&'r SerializedEvtxRecord<String>> for RowContents {
level: event.system().level().to_string(),
timestamp: FormattableDatetime::from(record.timestamp).to_string(),
record_id: record.event_record_id.to_string(),
event_id: event.system().EventID().clone(),
event_id: event.system().EventID().to_string(),
raw_value: record.data.clone(),
user_id,
event,
Expand All @@ -238,11 +300,11 @@ impl<'r> From<&'r RowContents> for Row<'r> {
&contents.event_data[..],
]);

if !contents.user_id.is_empty() && ! contents.user_id.contains('-') {
if !contents.user_id.is_empty() && !contents.user_id.contains('-') {
if contents.user_id == "500" {
row = row.bold().red()
} else {
row = row.on_light_red()
row = row.fg(Color::Red)
}
}

Expand Down

0 comments on commit 4e6a08d

Please sign in to comment.