diff --git a/Readme.md b/Readme.md index 6a806ca..a771349 100644 --- a/Readme.md +++ b/Readme.md @@ -122,6 +122,8 @@ sudo oryx `e`: Edit a firewall rule. +`s`: Save firewall rules to `~/oryx/firewall.json` + `Enter`: Create or Save a firewall rule. ## ⚖️ License diff --git a/oryx-tui/src/handler.rs b/oryx-tui/src/handler.rs index 68a9fe6..bc92abe 100644 --- a/oryx-tui/src/handler.rs +++ b/oryx-tui/src/handler.rs @@ -3,9 +3,7 @@ use std::{thread, time::Duration}; use crate::{ app::{ActivePopup, App, AppResult}, event::Event, - export::export, filter::FocusedBlock, - notification::{Notification, NotificationLevel}, section::FocusedSection, }; use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; @@ -190,29 +188,6 @@ pub fn handle_key_events( } } - KeyCode::Char('s') => { - let app_packets = app.packets.lock().unwrap(); - if app_packets.is_empty() { - Notification::send( - "There is no packets".to_string(), - NotificationLevel::Info, - event_sender, - )?; - } else { - match export(&app_packets) { - Ok(_) => { - Notification::send( - "Packets exported to ~/oryx/capture file".to_string(), - NotificationLevel::Info, - event_sender, - )?; - } - Err(e) => { - Notification::send(e.to_string(), NotificationLevel::Error, event_sender)?; - } - } - } - } _ => { app.section.handle_keys(key_event, event_sender.clone())?; } diff --git a/oryx-tui/src/help.rs b/oryx-tui/src/help.rs index 3685a8d..bd68290 100644 --- a/oryx-tui/src/help.rs +++ b/oryx-tui/src/help.rs @@ -57,6 +57,10 @@ impl Help { (Cell::from("## Firewall").bold().yellow(), ""), (Cell::from("n").bold(), "Add new firewall rule"), (Cell::from("e").bold(), "Edit a firewall rule"), + ( + Cell::from("s").bold(), + "Save firewall rules to ~/oryx/firewall.json ", + ), (Cell::from("Space").bold(), "Toggle firewall rule status"), (Cell::from("Enter").bold(), "Create or Save a firewall rule"), ], diff --git a/oryx-tui/src/section.rs b/oryx-tui/src/section.rs index 7be8994..1c080df 100644 --- a/oryx-tui/src/section.rs +++ b/oryx-tui/src/section.rs @@ -151,6 +151,9 @@ impl Section { Span::from("i").bold(), Span::from(" Infos").bold(), Span::from(" | ").bold(), + Span::from("s").bold(), + Span::from(" Save").bold(), + Span::from(" | ").bold(), Span::from("f").bold(), Span::from(" Filters").bold(), Span::from(" | ").bold(), @@ -176,6 +179,9 @@ impl Section { Span::from("e").bold(), Span::from(" Edit").bold(), Span::from(" | ").bold(), + Span::from("s").bold(), + Span::from(" Save").bold(), + Span::from(" | ").bold(), Span::from("󱁐 ").bold(), Span::from(" Toggle").bold(), Span::from(" | ").bold(), @@ -275,7 +281,9 @@ impl Section { }, _ => match self.focused_section { - FocusedSection::Inspection => self.inspection.handle_keys(key_event), + FocusedSection::Inspection => self + .inspection + .handle_keys(key_event, notification_sender.clone())?, FocusedSection::Firewall => self .firewall .handle_keys(key_event, notification_sender.clone())?, diff --git a/oryx-tui/src/section/firewall.rs b/oryx-tui/src/section/firewall.rs index 94b1338..b2dc984 100644 --- a/oryx-tui/src/section/firewall.rs +++ b/oryx-tui/src/section/firewall.rs @@ -330,15 +330,15 @@ impl Firewall { if !self.rules.is_empty() { info!("Saving Firewall Rules"); - let json = serde_json::to_string(&self.rules).unwrap(); + let json = serde_json::to_string(&self.rules)?; - let uid = unsafe { libc::geteuid() }; + let user_uid = unsafe { libc::geteuid() }; let oryx_export_dir = dirs::home_dir().unwrap().join("oryx"); if !oryx_export_dir.exists() { fs::create_dir(&oryx_export_dir)?; - chown(&oryx_export_dir, Some(uid), Some(uid))?; + chown(&oryx_export_dir, Some(user_uid), Some(user_uid))?; } let oryx_export_file = oryx_export_dir.join("firewall.json"); @@ -349,24 +349,23 @@ impl Firewall { } fn load_saved_rules() -> AppResult> { - info!("Loading Firewall Rules"); let oryx_export_file = dirs::home_dir().unwrap().join("oryx").join("firewall.json"); if oryx_export_file.exists() { - info!("Found previously saved Firewall Rules"); + info!("Loading Firewall Rules"); let json_string = fs::read_to_string(oryx_export_file)?; let mut parsed_rules: Vec = serde_json::from_str(&json_string)?; // as we don't know if ingress/egress programs are loaded we have to disable all rules - for rule in &mut parsed_rules { - rule.enabled = false - } + parsed_rules + .iter_mut() + .for_each(|rule| rule.enabled = false); info!("Firewall Rules loaded"); Ok(parsed_rules) } else { - info!("No saved Firewall Rules found"); + info!("Firewall Rules file not found"); Ok(Vec::new()) } } @@ -556,6 +555,24 @@ impl Firewall { self.add_rule(); } + KeyCode::Char('s') => match self.save_rules() { + Ok(_) => { + Notification::send( + "Firewall rules saved to ~/oryx/firewall.json file", + crate::notification::NotificationLevel::Info, + sender.clone(), + )?; + } + Err(e) => { + Notification::send( + "Error while saving firewall rules.", + crate::notification::NotificationLevel::Error, + sender.clone(), + )?; + error!("Error while saving firewall rules. {}", e); + } + }, + KeyCode::Char('e') => { if let Some(index) = self.state.selected() { let rule = self.rules[index].clone(); diff --git a/oryx-tui/src/section/inspection.rs b/oryx-tui/src/section/inspection.rs index 79bb9ae..8e02533 100644 --- a/oryx-tui/src/section/inspection.rs +++ b/oryx-tui/src/section/inspection.rs @@ -14,7 +14,10 @@ use ratatui::{ use tui_input::backend::crossterm::EventHandler; use crate::{ + app::AppResult, + export, filter::fuzzy::{self, Fuzzy}, + notification::{Notification, NotificationLevel}, packet::{ network::{IpPacket, IpProto}, AppPacket, @@ -56,7 +59,11 @@ impl Inspection { } } - pub fn handle_keys(&mut self, key_event: KeyEvent) { + pub fn handle_keys( + &mut self, + key_event: KeyEvent, + event_sender: kanal::Sender, + ) -> AppResult<()> { let fuzzy_is_enabled = { self.fuzzy.lock().unwrap().is_enabled() }; if fuzzy_is_enabled { @@ -126,9 +133,38 @@ impl Inspection { self.scroll_up(); } + KeyCode::Char('s') => { + let app_packets = self.packets.lock().unwrap(); + if app_packets.is_empty() { + Notification::send( + "There is no packets".to_string(), + NotificationLevel::Info, + event_sender, + )?; + } else { + match export::export(&app_packets) { + Ok(_) => { + Notification::send( + "Packets exported to ~/oryx/capture file".to_string(), + NotificationLevel::Info, + event_sender, + )?; + } + Err(e) => { + Notification::send( + e.to_string(), + NotificationLevel::Error, + event_sender, + )?; + } + } + } + } + _ => {} } } + Ok(()) } pub fn scroll_up(&mut self) {