diff --git a/Cargo.toml b/Cargo.toml index 11928c4..d86cd70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ argparse = "0.2.2" base64 = "0.21.4" dirs = "5.0.1" eyre = "0.6.8" -ircparser = "0.2.1" +ircparser = { git = "https://forgejo.vanten-s.com/vanten-s/ircparser" } openssl = "0.10" pgp = "0.10.2" rand = "0.8.5" diff --git a/src/client_handler.rs b/src/client_handler.rs index 52932ee..2776e42 100644 --- a/src/client_handler.rs +++ b/src/client_handler.rs @@ -1,10 +1,41 @@ use crate::helpers::bytes_to_privmsg_base64; -use crate::{encryption, helpers}; +use crate::{encryption, helpers, State}; use eyre::Result; use pgp::{Deserializable, SignedPublicKey}; use std::collections::HashMap; use std::sync::mpsc::{Receiver, Sender}; +#[derive(Debug)] +struct InvalidCommand; + +impl std::fmt::Display for InvalidCommand { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Ok(()) + } +} + +impl std::error::Error for InvalidCommand {} + +fn parse_bouncer_command(message: String, state: &mut State) -> Result<()> { + macro_rules! unwrap_option { + ($t:expr) => { + match $t { + Some(val) => val, + None => return Err(InvalidCommand.into()), + } + }; + } + + let mut splitted = message.split(' '); + match unwrap_option!(splitted.next()) { + "ALLOW_UNENCRYPTED" => state + .nicks_without_encryption + .push(unwrap_option!(splitted.next()).to_string().to_lowercase()), + _ => return Err(InvalidCommand.into()), + }; + Ok(()) +} + pub fn handle_message_from_client( recieved: &str, public_key: &Vec, @@ -14,10 +45,34 @@ pub fn handle_message_from_client( writer_channel_rx: &Receiver, listener_channel_tx: &Sender, _listener_channel_rx: &Receiver, + state: &mut State, ) -> Result<()> { - let command = &ircparser::parse(recieved).expect("Got an invalid IRC instruction")[0]; + let mut recieved = recieved.to_string(); + + if recieved.split(' ').count() == 1 { + recieved += " "; + } + + let parsed = ircparser::parse(&recieved); + let command = match parsed { + Ok(val) => val[0].clone(), + Err(_) => { + writer_channel_tx.send(recieved)?; + return Ok(()); + } + }; if command.command == "PRIVMSG" && !command.params[0].starts_with('#') { + if command.params[0] == "BOUNCER" { + return parse_bouncer_command(command.params[1].clone(), state); + } + if state + .nicks_without_encryption + .contains(&command.params[0].to_lowercase()) + { + writer_channel_tx.send(recieved)?; + return Ok(()); + } let other = &command.params[0]; if !keys.contains_key(other) { diff --git a/src/helpers.rs b/src/helpers.rs index 412f820..7cb3b8e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,7 +3,7 @@ use eyre::Result; use std::sync::mpsc::{self, Receiver, Sender}; #[derive(Debug)] -struct IrcParseError; +pub struct IrcParseError; impl std::fmt::Display for IrcParseError { fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -35,6 +35,22 @@ macro_rules! unwrap_or_return_option { }; } +pub struct State { + pub nicks_without_encryption: Vec, +} + +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, diff --git a/src/main.rs b/src/main.rs index d983e1d..c6230a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use argparse::{ArgumentParser, Store}; use dirs::config_local_dir; use eyre::Result; +use helpers::State; use pgp::{Deserializable, SignedPublicKey, SignedSecretKey}; use std::collections::HashMap; use std::fs; @@ -81,7 +82,11 @@ fn main() -> Result<()> { let tmp_port = port.clone(); thread::spawn(move || { - listener_server::listen_to_client(listener_channel_send_tx, listener_channel_recv_rx, tmp_port) + listener_server::listen_to_client( + listener_channel_send_tx, + listener_channel_recv_rx, + tmp_port, + ) }); let tmp_port = server_port.clone(); let tmp_server = server.clone(); @@ -95,6 +100,7 @@ fn main() -> Result<()> { }); let mut keys: HashMap = HashMap::new(); + let mut state = State::new(); loop { match listener_channel_rx.try_recv() { @@ -108,6 +114,7 @@ fn main() -> Result<()> { &writer_channel_rx, &listener_channel_tx, &listener_channel_rx, + &mut state, ); } Err(error) => match error { @@ -129,6 +136,7 @@ fn main() -> Result<()> { &writer_channel_rx, &listener_channel_tx, &listener_channel_rx, + &mut state, ); } Err(error) => match error { diff --git a/src/server_handler.rs b/src/server_handler.rs index c5e545e..9e7c4f7 100644 --- a/src/server_handler.rs +++ b/src/server_handler.rs @@ -1,5 +1,6 @@ use crate::unwrap_or_return_option; use crate::unwrap_or_return_result; +use crate::State; use crate::{encryption, helpers}; use eyre::Result; use pgp::{Deserializable, SignedPublicKey, SignedSecretKey}; @@ -25,15 +26,20 @@ pub fn handle_message_from_server( writer_channel_rx: &Receiver, listener_channel_tx: &Sender, _listener_channel_rx: &Receiver, + state: &mut State, ) -> Result<()> { let recieved_parsed = &unwrap_or_return_result!(ircparser::parse(recieved))[0]; + let default_reciever = String::new(); + + let reciever = match recieved_parsed.params.get(0) { + Some(val) => val, + None => &default_reciever, + }; + if recieved_parsed.command != "PRIVMSG" - || recieved_parsed - .params - .get(0) - .unwrap_or(&String::new()) - .starts_with('#') + || reciever.starts_with('#') + || state.nicks_without_encryption.contains(&reciever) { forward(recieved, listener_channel_tx, server)?; return Ok(());