refactor, added ip validation
This commit is contained in:
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -17,6 +17,15 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
@@ -459,6 +468,35 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.26"
|
||||
@@ -585,6 +623,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"ratatui",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -6,6 +6,7 @@ edition = "2024"
|
||||
[dependencies]
|
||||
color-eyre = "0.6.5"
|
||||
ratatui = "0.29.0"
|
||||
regex = "1.11.2"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use crate::app::status::EntryCreation;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
io::ErrorKind,
|
||||
num::{IntErrorKind, ParseIntError},
|
||||
};
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Entry {
|
||||
@@ -25,18 +22,26 @@ impl Display for Entry {
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
pub fn new(fromIP: String, toIP: String, fromPort: String, toPort: String) -> Option<Self> {
|
||||
if fromPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
|
||||
&& toPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
|
||||
pub fn new(
|
||||
fromIP: String,
|
||||
toIP: String,
|
||||
fromPort: String,
|
||||
toPort: String,
|
||||
) -> Result<Self, EntryCreation> {
|
||||
let ip = Regex::new("/^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$/").unwrap();
|
||||
if !fromPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
|
||||
|| !toPort.parse::<i32>().is_ok_and(|a| a > 1 && a < 65535)
|
||||
{
|
||||
Some(Entry {
|
||||
Err(EntryCreation::PortValidationError)
|
||||
} else if !ip.is_match(&fromIP) || !ip.is_match(&toIP) {
|
||||
Err(EntryCreation::IPValidationError)
|
||||
} else {
|
||||
Ok(Entry {
|
||||
fromIP,
|
||||
toIP,
|
||||
fromPort,
|
||||
toPort,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ pub struct AppState {
|
||||
pub toIP: String,
|
||||
pub toPort: String,
|
||||
pub screen: CurrentScreen,
|
||||
pub field: Option<EditingField>,
|
||||
// pub current: Option<Entry>,
|
||||
pub currentlyEditing: Option<EditingField>,
|
||||
pub entries: Vec<Entry>,
|
||||
pub confDir: String,
|
||||
@@ -32,7 +30,6 @@ impl AppState {
|
||||
toPort: String::new(),
|
||||
currentlyEditing: None,
|
||||
screen: CurrentScreen::Main,
|
||||
field: None,
|
||||
entries: settings.entries,
|
||||
confDir: confDir,
|
||||
}
|
||||
@@ -45,7 +42,7 @@ impl AppState {
|
||||
self.fromPort.clone(),
|
||||
self.toPort.clone(),
|
||||
) {
|
||||
Some(entry) => {
|
||||
Ok(entry) => {
|
||||
self.entries.push(entry);
|
||||
self.fromIP = String::new();
|
||||
self.toIP = String::new();
|
||||
@@ -59,17 +56,6 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startEditing(&mut self) {
|
||||
if let Some(currentField) = &self.currentlyEditing {
|
||||
match currentField {
|
||||
EditingField::ToIP => {}
|
||||
_ => self.currentlyEditing = Some(EditingField::FromIP),
|
||||
}
|
||||
} else {
|
||||
self.currentlyEditing = Some(EditingField::FromIP);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nextField(&mut self) {
|
||||
if let Some(currentField) = &self.currentlyEditing {
|
||||
self.currentlyEditing = match currentField {
|
||||
|
||||
@@ -25,7 +25,7 @@ impl Settings {
|
||||
Err(_) => {
|
||||
let newSet = Settings { entries: vec![] };
|
||||
let payload = serde_json::to_string_pretty(&newSet).unwrap();
|
||||
std::fs::write(config, payload);
|
||||
let _ = std::fs::write(config, payload);
|
||||
newSet
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,6 @@ impl Settings {
|
||||
|
||||
pub fn save(&self, config: &String) {
|
||||
let payload = serde_json::to_string(self).unwrap();
|
||||
std::fs::write(config, payload);
|
||||
let _ = std::fs::write(config, payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#[allow(non_snake_case)]
|
||||
#![allow(non_snake_case)]
|
||||
mod app;
|
||||
mod ui;
|
||||
|
||||
@@ -114,7 +114,7 @@ fn runApp<B: Backend>(app: &mut AppState, terminal: &mut Terminal<B>) -> Result<
|
||||
(KeyModifiers::NONE, KeyCode::Tab) => app.nextField(),
|
||||
(KeyModifiers::SHIFT, KeyCode::Tab) => app.prevField(),
|
||||
|
||||
(m, KeyCode::Char(v)) => {
|
||||
(_, KeyCode::Char(v)) => {
|
||||
if let Some(e) = &app.currentlyEditing {
|
||||
let mut isIP = false;
|
||||
let opField = match e {
|
||||
|
||||
23
src/ui/centeredRect.rs
Normal file
23
src/ui/centeredRect.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
|
||||
pub fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
||||
// Cut the given rectangle into three vertical pieces
|
||||
let popup_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
Constraint::Percentage(percent_y),
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
])
|
||||
.split(r);
|
||||
|
||||
// Then cut the middle vertical piece into three width-wise pieces
|
||||
Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
Constraint::Percentage(percent_x),
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
])
|
||||
.split(popup_layout[1])[1] // Return the middle chunk
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
#![allow(non_snake_case)]
|
||||
mod centeredRect;
|
||||
|
||||
use ratatui::{
|
||||
Frame,
|
||||
layout::{Constraint, Layout},
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Style},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph},
|
||||
};
|
||||
use ratatui::{
|
||||
layout::{Direction, Rect},
|
||||
widgets::Wrap,
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
|
||||
};
|
||||
|
||||
use crate::app::status::CurrentScreen;
|
||||
use crate::app::{AppState, status::EditingField};
|
||||
use crate::ui::centeredRect::centered_rect;
|
||||
|
||||
pub fn ui(frame: &mut Frame, app: &AppState) {
|
||||
let chunks = Layout::default()
|
||||
@@ -131,7 +130,6 @@ pub fn ui(frame: &mut Frame, app: &AppState) {
|
||||
EditingField::ToIP => "To IP",
|
||||
EditingField::FromPort => "From Port",
|
||||
EditingField::ToPort => "To Port",
|
||||
_ => "Something ",
|
||||
};
|
||||
Span::styled(
|
||||
format!("Editing: {curEdit}"),
|
||||
@@ -170,25 +168,3 @@ pub fn ui(frame: &mut Frame, app: &AppState) {
|
||||
frame.render_widget(helpFooter, footerChunks[0]);
|
||||
frame.render_widget(keyBindFooter, footerChunks[1]);
|
||||
}
|
||||
|
||||
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
||||
// Cut the given rectangle into three vertical pieces
|
||||
let popup_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
Constraint::Percentage(percent_y),
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
])
|
||||
.split(r);
|
||||
|
||||
// Then cut the middle vertical piece into three width-wise pieces
|
||||
Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
Constraint::Percentage(percent_x),
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
])
|
||||
.split(popup_layout[1])[1] // Return the middle chunk
|
||||
}
|
||||
Reference in New Issue
Block a user