e2e-irc/src/helpers.rs

145 lines
3.9 KiB
Rust

use base64::{engine::general_purpose, Engine as _};
use eyre::Result;
use std::sync::mpsc::{self, Receiver, Sender};
#[derive(Debug)]
pub struct IrcParseError;
impl std::fmt::Display for IrcParseError {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
impl std::error::Error for IrcParseError {}
static MAX_LENGTH: usize = 300;
#[macro_export]
macro_rules! unwrap_or_return_result {
($e:expr) => {
match $e {
Ok(val) => val,
Err(_) => return Ok(()),
}
};
}
#[macro_export]
macro_rules! unwrap_or_return_option {
($e:expr) => {
match $e {
Some(val) => val,
None => return Ok(()),
}
};
}
pub struct State {
pub nicks_without_encryption: Vec<String>,
}
impl State {
pub fn new() -> Self {
State {
nicks_without_encryption: vec![
"nickserv".to_string(),
"chanserv".to_string(),
"hostserv".to_string(),
],
}
}
}
fn forward(
message: String,
stream: &Sender<String>,
server_local: &str,
server_forward: &str,
) -> Result<(), mpsc::SendError<String>> {
match ircparser::parse(&message) {
Ok(val) => match val[0].command.as_str() {
"PRIVMSG" => stream.send(message),
_ => stream.send(message.replace(server_local, server_forward)),
},
Err(_) => stream.send(message.replace(server_local, server_forward)),
}
}
pub fn bytes_to_privmsg_base64(message: &Vec<u8>, reciever: &str) -> String {
let message_length = MAX_LENGTH - format!("PRIVMSG {reciever} :\r\n").len();
let encoded = general_purpose::STANDARD.encode(message);
let mut command = String::new();
for line in encoded
.chars()
.collect::<Vec<char>>()
.chunks(message_length)
.map(|c| c.iter().collect::<String>())
{
dbg!(&line);
command.push_str(&format!("PRIVMSG {reciever} :{line}\r\n"));
}
println!("{}", encoded);
println!("{}", command);
command
}
pub fn send_key(sender: &Sender<String>, reciever: &str, key: &Vec<u8>) -> Result<()> {
sender.send(format!("PRIVMSG {reciever} :START_KEY\r\n"))?;
sender.send(bytes_to_privmsg_base64(key, reciever))?;
sender.send(format!("PRIVMSG {reciever} :END_KEY\r\n"))?;
Ok(())
}
pub fn get_nick(userstring: &str) -> Option<String> {
let userstring = userstring.chars().collect::<Vec<char>>();
let start_pos = userstring.iter().position(|&x| x == ':')? + 1;
let end_pos = userstring.iter().position(|&x| x == '!')?;
Some(userstring[start_pos..end_pos].iter().collect::<String>())
}
pub fn recieve_message_base64(
writer_channel_rx: &Receiver<String>,
forward_stream: &Sender<String>,
server_local: &str,
server_forward: &str,
sender: &str,
end: &str,
) -> Result<Vec<u8>> {
let mut message: Vec<String> = Vec::new();
while !message.contains(&end.to_string()) {
let recieved_raw = writer_channel_rx.recv()?;
let parse_result = ircparser::parse(&recieved_raw);
let recieved = match parse_result {
Ok(mut val) => val.pop_back().unwrap(),
Err(_) => return Err(IrcParseError.into()),
};
let begin_source_reciever = format!(":{sender}!");
if recieved.command != "PRIVMSG"
|| !recieved
.source
.clone()
.unwrap_or("".to_string())
.starts_with(&begin_source_reciever)
|| recieved.params[0].starts_with('#')
{
forward(recieved_raw, forward_stream, server_local, server_forward)?;
continue;
}
message.push(recieved.params[1].clone());
}
message.pop();
let foreign_key = dbg!(message.concat());
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
Ok(foreign_key)
}