cleanup
This commit is contained in:
parent
f1e1d9ec90
commit
61db822921
@ -1,10 +0,0 @@
|
|||||||
use anyhow::{Context, Result};
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Read signatures file
|
|
||||||
pub fn read_signatures(path: &str) -> Result<Vec<String>> {
|
|
||||||
// Read path
|
|
||||||
let content = fs::read_to_string(path)
|
|
||||||
.with_context(|| format!("Could not read signatures file {}", path))?;
|
|
||||||
Ok(content.lines().map(String::from).collect())
|
|
||||||
}
|
|
@ -1,8 +1,7 @@
|
|||||||
use anyhow::{anyhow, Context, Result};
|
|
||||||
use rand::Rng;
|
|
||||||
use regex::Regex;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
|
use rand::Rng;
|
||||||
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Payload {
|
pub enum Payload {
|
||||||
@ -23,16 +22,14 @@ pub fn parse_signatures(file_path: &str) -> Result<Vec<Signature>> {
|
|||||||
for (index, line) in reader.lines().enumerate() {
|
for (index, line) in reader.lines().enumerate() {
|
||||||
let line = line.context("Failed to read line from signatures file")?;
|
let line = line.context("Failed to read line from signatures file")?;
|
||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
continue; // Skip empty lines
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = if line.contains('(') && line.contains(')') {
|
let payload = if line.contains('(') && line.contains(')') {
|
||||||
Payload::Regex(line)
|
Payload::Regex(line)
|
||||||
} else {
|
} else {
|
||||||
Payload::Raw(
|
Payload::Raw(unescape_string(&line)
|
||||||
unescape_string(&line)
|
.with_context(|| format!("Invalid payload on line {}", index + 1))?)
|
||||||
.with_context(|| format!("Invalid payload on line {}", index + 1))?,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
signatures.push(Signature { payload });
|
signatures.push(Signature { payload });
|
||||||
@ -53,13 +50,12 @@ fn unescape_string(s: &str) -> Result<Vec<u8>> {
|
|||||||
if c == '\\' {
|
if c == '\\' {
|
||||||
match chars.next() {
|
match chars.next() {
|
||||||
Some('x') => {
|
Some('x') => {
|
||||||
let hex = chars
|
let hex = chars.next().and_then(|c1| {
|
||||||
.next()
|
chars.next().map(|c2| format!("{}{}", c1, c2))
|
||||||
.and_then(|c1| chars.next().map(|c2| format!("{}{}", c1, c2)))
|
}).unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|| {
|
|
||||||
result.push(b'\\');
|
result.push(b'\\');
|
||||||
result.push(b'x');
|
result.push(b'x');
|
||||||
return String::new();
|
String::new()
|
||||||
});
|
});
|
||||||
if !hex.is_empty() {
|
if !hex.is_empty() {
|
||||||
if let Ok(byte) = u8::from_str_radix(&hex, 16) {
|
if let Ok(byte) = u8::from_str_radix(&hex, 16) {
|
||||||
@ -70,7 +66,7 @@ fn unescape_string(s: &str) -> Result<Vec<u8>> {
|
|||||||
result.extend(hex.bytes());
|
result.extend(hex.bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Some('0') => result.push(0),
|
Some('0') => result.push(0),
|
||||||
Some('n') => result.push(b'\n'),
|
Some('n') => result.push(b'\n'),
|
||||||
Some('r') => result.push(b'\r'),
|
Some('r') => result.push(b'\r'),
|
||||||
@ -94,7 +90,6 @@ pub fn generate_payload(signature: &Signature) -> Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_regex_match(regex_str: &str) -> Vec<u8> {
|
fn generate_regex_match(regex_str: &str) -> Vec<u8> {
|
||||||
// Simplified regex matching that doesn't rely on the regex crate
|
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let mut chars = regex_str.chars().peekable();
|
let mut chars = regex_str.chars().peekable();
|
||||||
|
|
||||||
@ -106,10 +101,7 @@ fn generate_regex_match(regex_str: &str) -> Vec<u8> {
|
|||||||
'd' => result.push(rand::thread_rng().gen_range(b'0'..=b'9') as char),
|
'd' => result.push(rand::thread_rng().gen_range(b'0'..=b'9') as char),
|
||||||
'w' => result.push(rand::thread_rng().gen_range(b'a'..=b'z') as char),
|
'w' => result.push(rand::thread_rng().gen_range(b'a'..=b'z') as char),
|
||||||
'x' => {
|
'x' => {
|
||||||
// Handle \x hex escapes
|
let hex = chars.next().and_then(|c1| chars.next().map(|c2| format!("{}{}", c1, c2)))
|
||||||
let hex = chars
|
|
||||||
.next()
|
|
||||||
.and_then(|c1| chars.next().map(|c2| format!("{}{}", c1, c2)))
|
|
||||||
.unwrap_or_else(|| "00".to_string());
|
.unwrap_or_else(|| "00".to_string());
|
||||||
if let Ok(byte) = u8::from_str_radix(&hex, 16) {
|
if let Ok(byte) = u8::from_str_radix(&hex, 16) {
|
||||||
result.push(byte as char);
|
result.push(byte as char);
|
||||||
@ -118,39 +110,25 @@ fn generate_regex_match(regex_str: &str) -> Vec<u8> {
|
|||||||
_ => result.push(next_char),
|
_ => result.push(next_char),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
'[' => {
|
'[' => {
|
||||||
let mut class = String::new();
|
let mut class = String::new();
|
||||||
while let Some(class_char) = chars.next() {
|
for class_char in chars.by_ref() {
|
||||||
if class_char == ']' {
|
if class_char == ']' { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
class.push(class_char);
|
class.push(class_char);
|
||||||
}
|
}
|
||||||
if !class.is_empty() {
|
if !class.is_empty() {
|
||||||
result.push(
|
result.push(class.chars().nth(rand::thread_rng().gen_range(0..class.len())).unwrap());
|
||||||
class
|
|
||||||
.chars()
|
|
||||||
.nth(rand::thread_rng().gen_range(0..class.len()))
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
'(' => {
|
'(' => {
|
||||||
// Skip capturing groups
|
|
||||||
let mut depth = 1;
|
let mut depth = 1;
|
||||||
while let Some(group_char) = chars.next() {
|
for group_char in chars.by_ref() {
|
||||||
if group_char == '(' {
|
if group_char == '(' { depth += 1; }
|
||||||
depth += 1;
|
if group_char == ')' { depth -= 1; }
|
||||||
}
|
if depth == 0 { break; }
|
||||||
if group_char == ')' {
|
|
||||||
depth -= 1;
|
|
||||||
}
|
|
||||||
if depth == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
'+' | '*' => {
|
'+' | '*' => {
|
||||||
if let Some(last_char) = result.chars().last() {
|
if let Some(last_char) = result.chars().last() {
|
||||||
let repeat = rand::thread_rng().gen_range(0..5);
|
let repeat = rand::thread_rng().gen_range(0..5);
|
||||||
@ -158,7 +136,7 @@ fn generate_regex_match(regex_str: &str) -> Vec<u8> {
|
|||||||
result.push(last_char);
|
result.push(last_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
'.' => result.push(rand::thread_rng().gen_range(b'!'..=b'~') as char),
|
'.' => result.push(rand::thread_rng().gen_range(b'!'..=b'~') as char),
|
||||||
_ => result.push(c),
|
_ => result.push(c),
|
||||||
}
|
}
|
||||||
@ -187,9 +165,6 @@ mod tests {
|
|||||||
assert_eq!(unescape_string(r"\0\r\n\t").unwrap(), b"\0\r\n\t");
|
assert_eq!(unescape_string(r"\0\r\n\t").unwrap(), b"\0\r\n\t");
|
||||||
assert_eq!(unescape_string(r"Incomplete\").unwrap(), b"Incomplete\\");
|
assert_eq!(unescape_string(r"Incomplete\").unwrap(), b"Incomplete\\");
|
||||||
assert_eq!(unescape_string(r"Incomplete\x").unwrap(), b"Incomplete\\x");
|
assert_eq!(unescape_string(r"Incomplete\x").unwrap(), b"Incomplete\\x");
|
||||||
assert_eq!(
|
assert_eq!(unescape_string(r"Incomplete\x4").unwrap(), b"Incomplete\\x4");
|
||||||
unescape_string(r"Incomplete\x4").unwrap(),
|
|
||||||
b"Incomplete\\x4"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,10 @@ use tokio::net::TcpListener;
|
|||||||
use tracing::{debug, error, info, Level};
|
use tracing::{debug, error, info, Level};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod config;
|
|
||||||
mod handler;
|
mod handler;
|
||||||
|
|
||||||
use cli::Cli;
|
use cli::Cli;
|
||||||
use handler::{generate_payload, parse_signatures, Signature};
|
use handler::{generate_payload, parse_signatures};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
Loading…
Reference in New Issue
Block a user