Compare commits
26 commits
87f2b142c9
...
e4fd3224cf
Author | SHA1 | Date | |
---|---|---|---|
vanten-s | e4fd3224cf | ||
vanten-s | 5c24ae5f96 | ||
vanten-s | c895210cea | ||
vanten-s | 4aed403c97 | ||
vanten-s | 247f35994b | ||
vanten-s | 6eeeb4a2e8 | ||
vanten-s | 2783cc9ca8 | ||
vanten-s | bdb14a5b6d | ||
vanten-s | 805caebe35 | ||
vanten-s | b9af753fc7 | ||
vanten-s | e26db6d68b | ||
vanten-s | 7c5bc94ade | ||
vanten-s | d38da05d05 | ||
vanten-s | 83b10eb3d5 | ||
vanten-s | b480ce09e5 | ||
vanten-s | e19e3b0d25 | ||
vanten-s | d185ceb7c0 | ||
vanten-s | 0a7b931bb9 | ||
vanten-s | cb87ebe318 | ||
vanten-s | 620ad761fd | ||
vanten-s | ca79a1e513 | ||
vanten-s | e83cf5bfb5 | ||
vanten-s | 72945e8b94 | ||
vanten-s | 6626110758 | ||
vanten-s | 34b2e0e5a9 | ||
vanten-s | 25b8f5b51e |
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
||||||
/target
|
/target
|
||||||
secret.gpg
|
Cargo.lock
|
||||||
public.gpg
|
|
||||||
|
|
1382
Cargo.lock
generated
1382
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
14
Cargo.toml
14
Cargo.toml
|
@ -1,13 +1,21 @@
|
||||||
[package]
|
[package]
|
||||||
name = "irc-e2e"
|
name = "e2e-irc"
|
||||||
version = "0.1.0"
|
version = "3.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0"
|
||||||
|
keywords = ["irc", "encryption"]
|
||||||
|
description = "An IRC bouncer that can send encrypted messages"
|
||||||
|
repository = "https://forgejo.vanten-s.com/vanten-s/e2e-irc/"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
argparse = "0.2.2"
|
||||||
base64 = "0.21.4"
|
base64 = "0.21.4"
|
||||||
ircparser = "0.2.1"
|
dirs = "5.0.1"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
ircparser-vanten = "0.2.1"
|
||||||
openssl = "0.10"
|
openssl = "0.10"
|
||||||
pgp = "0.10.2"
|
pgp = "0.10.2"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
toml = "0.8.2"
|
||||||
|
|
35
README.md
Normal file
35
README.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# e2e-irc
|
||||||
|
This is an IRC bouncer that supports end-to-end encryption and is horribly written.
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
e2e-irc uses a config file in `~/.config/e2e-irc/config.toml` on linux.
|
||||||
|
The configuration file is a toml file with two or three fields:
|
||||||
|
- public_key the location of the public pgp key
|
||||||
|
- secret_key the location of the secret pgp key
|
||||||
|
- passwd the password of the pgp key
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
```
|
||||||
|
e2e-irc [OPTIONS] SERVER
|
||||||
|
|
||||||
|
Encrypted IRC Bouncer
|
||||||
|
|
||||||
|
Positional arguments:
|
||||||
|
server The Address Of The Server The Bouncer Connects To
|
||||||
|
|
||||||
|
Optional arguments:
|
||||||
|
-h,--help Show this help message and exit
|
||||||
|
-p,--port PORT The Port The Bouncer Binds To
|
||||||
|
--sp,--server-port SERVER_PORT
|
||||||
|
The TLS Enabled Port Of The Server
|
||||||
|
```
|
||||||
|
|
||||||
|
# Install
|
||||||
|
```bash
|
||||||
|
cargo install e2e-irc
|
||||||
|
```
|
||||||
|
|
||||||
|
# Run
|
||||||
|
```bash
|
||||||
|
e2e-irc [OPTIONS] SERVER
|
||||||
|
```
|
104
src/client_handler.rs
Normal file
104
src/client_handler.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
use crate::helpers::bytes_to_privmsg_base64;
|
||||||
|
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<u8>,
|
||||||
|
server: &str,
|
||||||
|
keys: &mut HashMap<String, SignedPublicKey>,
|
||||||
|
writer_channel_tx: &Sender<String>,
|
||||||
|
writer_channel_rx: &Receiver<String>,
|
||||||
|
listener_channel_tx: &Sender<String>,
|
||||||
|
_listener_channel_rx: &Receiver<String>,
|
||||||
|
state: &mut State,
|
||||||
|
) -> Result<()> {
|
||||||
|
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) {
|
||||||
|
helpers::send_key(writer_channel_tx, other, public_key)?;
|
||||||
|
let key = helpers::recieve_message_base64(
|
||||||
|
writer_channel_rx,
|
||||||
|
listener_channel_tx,
|
||||||
|
"127.0.0.1",
|
||||||
|
server,
|
||||||
|
other,
|
||||||
|
"END_KEY",
|
||||||
|
)?;
|
||||||
|
let key = SignedPublicKey::from_bytes(key.as_slice())?;
|
||||||
|
keys.insert(other.to_string(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
let foreign_key = keys.get(other).unwrap();
|
||||||
|
|
||||||
|
writer_channel_tx.send(format!("PRIVMSG {other} START_MESSAGE\r\n"))?;
|
||||||
|
writer_channel_tx.send(bytes_to_privmsg_base64(
|
||||||
|
&encryption::encrypt(foreign_key, &command.params[1])?,
|
||||||
|
other,
|
||||||
|
))?;
|
||||||
|
writer_channel_tx.send(format!("PRIVMSG {other} END_MESSAGE\r\n"))?;
|
||||||
|
} else {
|
||||||
|
writer_channel_tx.send(recieved.replace("127.0.0.1", server))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
29
src/encryption.rs
Normal file
29
src/encryption.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use eyre::Result;
|
||||||
|
use pgp::crypto::sym::SymmetricKeyAlgorithm;
|
||||||
|
use pgp::ser::Serialize;
|
||||||
|
use pgp::{Deserializable, Message, SignedPublicKey, SignedSecretKey};
|
||||||
|
use rand::prelude::*;
|
||||||
|
|
||||||
|
pub fn encrypt(key: &SignedPublicKey, message: &str) -> Result<Vec<u8>, pgp::errors::Error> {
|
||||||
|
let message = Message::new_literal("none", message);
|
||||||
|
let mut rng = StdRng::from_entropy();
|
||||||
|
|
||||||
|
let message = message.encrypt_to_keys(&mut rng, SymmetricKeyAlgorithm::AES128, &[key])?;
|
||||||
|
|
||||||
|
message.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt<'a>(
|
||||||
|
key: &'a SignedSecretKey,
|
||||||
|
message: &[u8],
|
||||||
|
password: &'a str,
|
||||||
|
) -> Result<String, pgp::errors::Error> {
|
||||||
|
let message = Message::from_bytes(message)?; // Convert message bytes to message object
|
||||||
|
let message = message.decrypt(|| password.to_string(), &[key])?.0; // Decrypt
|
||||||
|
let message = message.map(|x| x.unwrap()).collect::<Vec<Message>>(); // Get all messages
|
||||||
|
let message = &message[0]; // Get first message
|
||||||
|
let message = message.get_content()?.unwrap_or(Vec::new()); // Get message content as Vec<u8>
|
||||||
|
let message = String::from_utf8(message).unwrap(); // Convert to String
|
||||||
|
|
||||||
|
Ok(message)
|
||||||
|
}
|
144
src/helpers.rs
Normal file
144
src/helpers.rs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
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)
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
use std::io::{ErrorKind, Read, Write};
|
use std::io::{ErrorKind, Read, Write};
|
||||||
use std::net::TcpListener;
|
use std::net::{TcpListener, TcpStream};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc::{self, TryRecvError};
|
||||||
|
use std::thread;
|
||||||
pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, port: &str) {
|
use std::time::Duration;
|
||||||
let listener = TcpListener::bind("127.0.0.1:".to_string() + port).unwrap();
|
|
||||||
let mut stream = listener.accept().unwrap().0;
|
|
||||||
|
|
||||||
stream
|
|
||||||
.set_nonblocking(true)
|
|
||||||
.expect("Couldn't set nonblocking");
|
|
||||||
|
|
||||||
|
fn stream_handler(tx: &mpsc::Sender<String>, rx: &mpsc::Receiver<String>, mut stream: TcpStream) {
|
||||||
loop {
|
loop {
|
||||||
let mut buffer: Vec<u8> = Vec::new();
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
let mut buf: [u8; 1] = [0];
|
let mut buf: [u8; 1] = [0];
|
||||||
|
@ -19,9 +14,10 @@ pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, po
|
||||||
match stream.read(&mut buf) {
|
match stream.read(&mut buf) {
|
||||||
Ok(_length) => buffer.push(buf[0]),
|
Ok(_length) => buffer.push(buf[0]),
|
||||||
Err(_error) => match _error.kind() {
|
Err(_error) => match _error.kind() {
|
||||||
ErrorKind::WouldBlock => {},
|
ErrorKind::WouldBlock => {}
|
||||||
_ => {
|
_ => {
|
||||||
dbg!(_error);
|
dbg!(_error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -29,13 +25,35 @@ pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, po
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
match stream.write_all(value.as_bytes()) {
|
match stream.write_all(value.as_bytes()) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(_e) => println!("Couldn't send {value}"),
|
Err(_e) => {
|
||||||
|
dbg!(_e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Err(_e) => {}
|
Err(TryRecvError::Empty) => {}
|
||||||
|
Err(TryRecvError::Disconnected) => return,
|
||||||
}
|
}
|
||||||
|
thread::sleep(Duration::from_micros(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = tx.send(String::from_utf8_lossy(&buffer).to_string());
|
let _ = tx.send(dbg!(String::from_utf8_lossy(&buffer).to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, port: String) {
|
||||||
|
let listener = TcpListener::bind("127.0.0.1:".to_string() + &port)
|
||||||
|
.expect(&("Couldn't start listener on 127.0.0.1 port ".to_string() + &port));
|
||||||
|
loop {
|
||||||
|
let (stream, ip) = listener.accept().unwrap();
|
||||||
|
println!("Got connection from {ip}");
|
||||||
|
|
||||||
|
stream
|
||||||
|
.set_nonblocking(true)
|
||||||
|
.expect("Couldn't set nonblocking");
|
||||||
|
|
||||||
|
stream_handler(&tx, &rx, stream);
|
||||||
|
println!("Closed connection with {ip}");
|
||||||
|
let _ = tx.send("DUMMY CLOSE_CONNECTION".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
352
src/main.rs
352
src/main.rs
|
@ -1,110 +1,78 @@
|
||||||
use base64::{engine::general_purpose, Engine as _};
|
use argparse::{ArgumentParser, Store};
|
||||||
use ircparser;
|
use dirs::config_local_dir;
|
||||||
use pgp::crypto::sym::SymmetricKeyAlgorithm;
|
use eyre::Result;
|
||||||
use pgp::ser::Serialize;
|
use helpers::State;
|
||||||
use pgp::{Deserializable, Message, SignedPublicKey, SignedSecretKey};
|
use pgp::{Deserializable, SignedPublicKey, SignedSecretKey};
|
||||||
use rand::prelude::*;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::{Shutdown, TcpStream};
|
use std::fs;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{env, fs};
|
use toml::Table;
|
||||||
|
|
||||||
|
mod client_handler;
|
||||||
|
mod encryption;
|
||||||
|
mod helpers;
|
||||||
mod listener_server;
|
mod listener_server;
|
||||||
|
mod server_handler;
|
||||||
mod writer_client;
|
mod writer_client;
|
||||||
|
|
||||||
macro_rules! try_recv {
|
fn main() -> Result<()> {
|
||||||
($rx:ident) => {
|
let config_file = config_local_dir()
|
||||||
match $rx.try_recv() {
|
.expect("Couldn't get config directory")
|
||||||
Ok(recieved) => recieved,
|
.join("e2e-irc/config.toml");
|
||||||
Err(_e) => match _e {
|
|
||||||
mpsc::TryRecvError::Empty => String::new(),
|
|
||||||
mpsc::TryRecvError::Disconnected => {
|
|
||||||
panic!("Error!")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bytes_to_privmsg_base64(message: Vec<u8>, reciever: &str) -> String {
|
if !config_file.exists() {
|
||||||
let mut command = String::new();
|
panic!("Create a config file at {}", config_file.display());
|
||||||
for line in general_purpose::STANDARD
|
|
||||||
.encode(message)
|
|
||||||
.chars()
|
|
||||||
.collect::<Vec<char>>()
|
|
||||||
.chunks(500)
|
|
||||||
.map(|c| c.iter().collect::<String>())
|
|
||||||
{
|
|
||||||
command.push_str(&format!("PRIVMSG {reciever} :{line}\r\n"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", command);
|
let parsed_config = String::from_utf8_lossy(&fs::read(config_file)?).parse::<Table>()?;
|
||||||
command
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encrypt(key: &SignedPublicKey, message: &str) -> Result<Vec<u8>, pgp::errors::Error> {
|
let public_key_location = parsed_config
|
||||||
let message = Message::new_literal("none", message);
|
.get("public_key")
|
||||||
let mut rng = StdRng::from_entropy();
|
.expect("Coudln't get public_key. Try creating it in the config")
|
||||||
|
.as_str()
|
||||||
|
.expect("Couldn't convert public_key to str");
|
||||||
|
let secret_key_location = parsed_config
|
||||||
|
.get("secret_key")
|
||||||
|
.expect("Coudln't get secret_key. Try creating it in the config")
|
||||||
|
.as_str()
|
||||||
|
.expect("Couldn't convert secret_key to str");
|
||||||
|
|
||||||
let message = message.encrypt_to_keys(&mut rng, SymmetricKeyAlgorithm::AES128, &[key])?;
|
let default_password = toml::Value::String(String::new());
|
||||||
|
|
||||||
Ok(message.to_bytes()?)
|
let passwd = parsed_config
|
||||||
}
|
.get("passwd")
|
||||||
|
.unwrap_or(&default_password)
|
||||||
|
.as_str()
|
||||||
|
.expect("Coudln't convert passwd to str");
|
||||||
|
|
||||||
fn decrypt<'a>(
|
let mut server = "irc.vanten-s.com".to_string();
|
||||||
key: &'a SignedSecretKey,
|
let mut port = "6666".to_string();
|
||||||
message: Vec<u8>,
|
let mut server_port = "6697".to_string();
|
||||||
password: &'a str,
|
|
||||||
) -> Result<String, pgp::errors::Error> {
|
|
||||||
let message = Message::from_bytes(message.as_slice())?; // Convert message bytes to message object
|
|
||||||
let message = message.decrypt(|| password.to_string(), &[key])?.0; // Decrypt
|
|
||||||
let message = message.map(|x| x.unwrap()).collect::<Vec<Message>>(); // Get all messages
|
|
||||||
let message = &message[0]; // Get first message
|
|
||||||
let message = message.get_content()?.unwrap_or(Vec::new()); // Get message content as Vec<u8>
|
|
||||||
let message = String::from_utf8(message).unwrap(); // Convert to String
|
|
||||||
|
|
||||||
Ok(message)
|
{
|
||||||
}
|
let mut ap = ArgumentParser::new();
|
||||||
|
ap.set_description("Encrypted IRC Bouncer");
|
||||||
|
ap.refer(&mut server)
|
||||||
|
.add_argument(
|
||||||
|
"server",
|
||||||
|
Store,
|
||||||
|
"The Address Of The Server The Bouncer Connects To",
|
||||||
|
)
|
||||||
|
.required();
|
||||||
|
ap.refer(&mut port)
|
||||||
|
.add_option(&["-p", "--port"], Store, "The Port The Bouncer Binds To");
|
||||||
|
ap.refer(&mut server_port).add_option(
|
||||||
|
&["--sp", "--server-port"],
|
||||||
|
Store,
|
||||||
|
"The TLS Enabled Port Of The Server",
|
||||||
|
);
|
||||||
|
ap.parse_args_or_exit();
|
||||||
|
}
|
||||||
|
|
||||||
fn get_nick(userstring: &str) -> String {
|
let public_key = fs::read(public_key_location)?;
|
||||||
let userstring = userstring.chars().collect::<Vec<char>>();
|
let secret_key = SignedSecretKey::from_bytes(fs::read(secret_key_location)?.as_slice())?;
|
||||||
let start_pos = userstring.iter().position(|&x| x == ':').unwrap() + 1;
|
|
||||||
let end_pos = userstring.iter().position(|&x| x == '!').unwrap();
|
|
||||||
userstring[start_pos..end_pos].iter().collect::<String>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut args = env::args().collect::<Vec<String>>();
|
|
||||||
|
|
||||||
let server = args[1].clone();
|
|
||||||
let port = args[2].clone();
|
|
||||||
|
|
||||||
let default_password = String::new();
|
|
||||||
let passwd = args.pop().unwrap_or(default_password);
|
|
||||||
|
|
||||||
let stream = TcpStream::connect(format!("{server}:6697"))?;
|
|
||||||
|
|
||||||
let public_key = fs::read("public.gpg")?;
|
|
||||||
let secret_key = SignedSecretKey::from_bytes(fs::read("secret.gpg")?.as_slice())?;
|
|
||||||
|
|
||||||
let reader_stream = match stream.try_clone() {
|
|
||||||
Ok(stream) => stream,
|
|
||||||
Err(_error) => {
|
|
||||||
let _ = stream.shutdown(Shutdown::Both);
|
|
||||||
panic!("Failed to create the reader stream")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let writer_stream = match stream.try_clone() {
|
|
||||||
Ok(stream) => stream,
|
|
||||||
Err(_error) => {
|
|
||||||
let _ = stream.shutdown(Shutdown::Both);
|
|
||||||
let _ = reader_stream.shutdown(Shutdown::Both);
|
|
||||||
panic!("Failed to create the writer stream")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let (listener_channel_send_tx, listener_channel_rx) = mpsc::channel();
|
let (listener_channel_send_tx, listener_channel_rx) = mpsc::channel();
|
||||||
let (listener_channel_tx, listener_channel_recv_rx) = mpsc::channel();
|
let (listener_channel_tx, listener_channel_recv_rx) = mpsc::channel();
|
||||||
|
@ -112,175 +80,71 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (writer_channel_tx, writer_channel_send_rx) = mpsc::channel();
|
let (writer_channel_tx, writer_channel_send_rx) = mpsc::channel();
|
||||||
let (writer_channel_recv_tx, writer_channel_rx) = mpsc::channel();
|
let (writer_channel_recv_tx, writer_channel_rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tmp_port = port.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
listener_server::listen_to_client(listener_channel_send_tx, listener_channel_recv_rx, &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();
|
let tmp_server = server.clone();
|
||||||
thread::spawn(|| {
|
thread::spawn(move || {
|
||||||
writer_client::write_to_server(
|
writer_client::write_to_server(
|
||||||
writer_stream,
|
&tmp_server,
|
||||||
tmp_server,
|
&tmp_port,
|
||||||
writer_channel_send_rx,
|
writer_channel_send_rx,
|
||||||
writer_channel_recv_tx,
|
writer_channel_recv_tx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut keys: HashMap<String, SignedPublicKey> = HashMap::new();
|
let mut keys: HashMap<String, SignedPublicKey> = HashMap::new();
|
||||||
let mut userstring = String::new();
|
let mut state = State::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let recieved = try_recv!(listener_channel_rx);
|
match listener_channel_rx.try_recv() {
|
||||||
|
Ok(message) => {
|
||||||
if !recieved.is_empty() {
|
let _ = client_handler::handle_message_from_client(
|
||||||
let command = &ircparser::parse(&recieved).expect("Got an invalid IRC instruction")[0];
|
&message,
|
||||||
|
&public_key,
|
||||||
if command.command == "PRIVMSG" && !command.params[0].starts_with("#") {
|
&server,
|
||||||
let reciever = &command.params[0];
|
&mut keys,
|
||||||
if !keys.contains_key(reciever) {
|
&writer_channel_tx,
|
||||||
writer_channel_tx.send(format!("PRIVMSG {reciever} :START_KEY\r\n"))?;
|
&writer_channel_rx,
|
||||||
|
&listener_channel_tx,
|
||||||
writer_channel_tx
|
&listener_channel_rx,
|
||||||
.send(bytes_to_privmsg_base64(public_key.clone(), reciever))?;
|
&mut state,
|
||||||
writer_channel_tx.send(format!("PRIVMSG {reciever} :END_KEY\r\n"))?;
|
);
|
||||||
|
|
||||||
let mut foreign_key: Vec<String> = Vec::new();
|
|
||||||
while !foreign_key.contains(&"END_KEY".to_string()) {
|
|
||||||
let recieved_raw = writer_channel_rx.recv()?;
|
|
||||||
|
|
||||||
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
|
|
||||||
let begin_source_reciever = format!(":{reciever}!");
|
|
||||||
if recieved.command != "PRIVMSG"
|
|
||||||
|| !recieved
|
|
||||||
.source
|
|
||||||
.clone()
|
|
||||||
.unwrap_or("".to_string())
|
|
||||||
.starts_with(&begin_source_reciever)
|
|
||||||
{
|
|
||||||
listener_channel_tx.send(recieved_raw)?;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreign_key.push(recieved.params[1].clone());
|
|
||||||
}
|
|
||||||
foreign_key.pop();
|
|
||||||
|
|
||||||
println!("Got a foreign key from {reciever}");
|
|
||||||
let foreign_key = foreign_key.concat();
|
|
||||||
dbg!(&foreign_key);
|
|
||||||
|
|
||||||
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
|
|
||||||
|
|
||||||
dbg!("It's decoded");
|
|
||||||
|
|
||||||
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
|
|
||||||
|
|
||||||
dbg!("And I now got it's SignedPublicKey format");
|
|
||||||
|
|
||||||
keys.insert(reciever.to_string(), key);
|
|
||||||
}
|
|
||||||
|
|
||||||
let foreign_key = keys.get(reciever).unwrap();
|
|
||||||
|
|
||||||
writer_channel_tx.send(format!("PRIVMSG {reciever} START_MESSAGE\r\n"))?;
|
|
||||||
writer_channel_tx.send(bytes_to_privmsg_base64(
|
|
||||||
encrypt(&foreign_key, &command.params[1])?,
|
|
||||||
reciever,
|
|
||||||
))?;
|
|
||||||
writer_channel_tx.send(format!("PRIVMSG {reciever} END_MESSAGE\r\n"))?;
|
|
||||||
} else {
|
|
||||||
writer_channel_tx.send(recieved.replace("127.0.0.1", &server))?;
|
|
||||||
}
|
}
|
||||||
}
|
Err(error) => match error {
|
||||||
|
mpsc::TryRecvError::Empty => {}
|
||||||
|
mpsc::TryRecvError::Disconnected => panic!("listener_channel_rx disconnected"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let recieved = try_recv!(writer_channel_rx);
|
match writer_channel_rx.try_recv() {
|
||||||
if !recieved.is_empty() {
|
Ok(message) => {
|
||||||
let recieved_parsed = &ircparser::parse(&recieved).unwrap()[0];
|
let _ = server_handler::handle_message_from_server(
|
||||||
|
&message,
|
||||||
if recieved_parsed.command != "PRIVMSG"
|
&public_key,
|
||||||
|| recieved_parsed
|
&secret_key,
|
||||||
.params
|
&server,
|
||||||
.get(0)
|
passwd,
|
||||||
.unwrap_or(&String::new())
|
&mut keys,
|
||||||
.starts_with("#")
|
&writer_channel_tx,
|
||||||
{
|
&writer_channel_rx,
|
||||||
listener_channel_tx.send(recieved.replace(&server, "127.0.0.1"))?;
|
&listener_channel_tx,
|
||||||
continue;
|
&listener_channel_rx,
|
||||||
|
&state,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Err(error) => match error {
|
||||||
|
mpsc::TryRecvError::Empty => {}
|
||||||
|
mpsc::TryRecvError::Disconnected => panic!("writer_channel_rx disconnected"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
dbg!(&recieved_parsed);
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
|
||||||
if recieved_parsed.params[1] == "START_MESSAGE" {
|
|
||||||
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
|
|
||||||
let sample_privmsg = recieved.clone();
|
|
||||||
|
|
||||||
let mut encrypted_message: Vec<String> = Vec::new();
|
|
||||||
while !encrypted_message.contains(&"END_MESSAGE".to_string()) {
|
|
||||||
let recieved_raw = writer_channel_rx.recv()?;
|
|
||||||
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
|
|
||||||
|
|
||||||
let begin_source_reciever = format!(":{reciever}!");
|
|
||||||
if recieved.command != "PRIVMSG"
|
|
||||||
|| !recieved
|
|
||||||
.source
|
|
||||||
.clone()
|
|
||||||
.unwrap_or("".to_string())
|
|
||||||
.starts_with(&begin_source_reciever)
|
|
||||||
{
|
|
||||||
listener_channel_tx.send(recieved_raw.replace(&server, "127.0.0.1"))?;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
encrypted_message.push(recieved.params[1].clone());
|
|
||||||
}
|
|
||||||
encrypted_message.pop();
|
|
||||||
|
|
||||||
let encrypted_message = encrypted_message.join("");
|
|
||||||
let encrypted_message = general_purpose::STANDARD.decode(encrypted_message)?;
|
|
||||||
|
|
||||||
let decrypted_message = decrypt(&secret_key, encrypted_message, &passwd)?;
|
|
||||||
listener_channel_tx
|
|
||||||
.send(sample_privmsg.replace("START_MESSAGE", &decrypted_message))?;
|
|
||||||
} else if recieved_parsed.params[1] == "START_KEY" {
|
|
||||||
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
|
|
||||||
let to_send = bytes_to_privmsg_base64(public_key.clone(), &reciever);
|
|
||||||
writer_channel_tx.send(to_send)?;
|
|
||||||
writer_channel_tx.send(format!("PRIVMSG {reciever} END_KEY\r\n"))?;
|
|
||||||
|
|
||||||
dbg!("Started Getting a key");
|
|
||||||
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
|
|
||||||
let mut foreign_key: Vec<String> = Vec::new();
|
|
||||||
while !foreign_key.contains(&"END_KEY".to_string()) {
|
|
||||||
let recieved_raw = writer_channel_rx.recv()?;
|
|
||||||
|
|
||||||
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
|
|
||||||
let begin_source_reciever = format!(":{reciever}!");
|
|
||||||
if recieved.command != "PRIVMSG"
|
|
||||||
|| !recieved
|
|
||||||
.source
|
|
||||||
.clone()
|
|
||||||
.unwrap_or("".to_string())
|
|
||||||
.starts_with(&begin_source_reciever)
|
|
||||||
{
|
|
||||||
listener_channel_tx.send(recieved_raw.replace(&server, "127.0.0.1"))?;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreign_key.push(recieved.params[1].clone());
|
|
||||||
}
|
|
||||||
foreign_key.pop();
|
|
||||||
dbg!("Got a foreign key from");
|
|
||||||
dbg!(&reciever);
|
|
||||||
|
|
||||||
let foreign_key = foreign_key.concat();
|
|
||||||
|
|
||||||
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
|
|
||||||
dbg!("Decoded the key");
|
|
||||||
|
|
||||||
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
|
|
||||||
dbg!("Deserialized the key");
|
|
||||||
|
|
||||||
keys.insert(reciever.to_string(), key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
87
src/server_handler.rs
Normal file
87
src/server_handler.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
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};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
|
||||||
|
fn forward(
|
||||||
|
message: &str,
|
||||||
|
listener_channel_tx: &Sender<String>,
|
||||||
|
server: &str,
|
||||||
|
) -> Result<(), mpsc::SendError<String>> {
|
||||||
|
listener_channel_tx.send(message.replace(server, "127.0.0.1"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_message_from_server(
|
||||||
|
recieved: &str,
|
||||||
|
public_key: &Vec<u8>,
|
||||||
|
secret_key: &SignedSecretKey,
|
||||||
|
server: &str,
|
||||||
|
passwd: &str,
|
||||||
|
keys: &mut HashMap<String, SignedPublicKey>,
|
||||||
|
writer_channel_tx: &Sender<String>,
|
||||||
|
writer_channel_rx: &Receiver<String>,
|
||||||
|
listener_channel_tx: &Sender<String>,
|
||||||
|
_listener_channel_rx: &Receiver<String>,
|
||||||
|
state: &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"
|
||||||
|
|| reciever.starts_with('#')
|
||||||
|
|| state.nicks_without_encryption.contains(reciever)
|
||||||
|
{
|
||||||
|
forward(recieved, listener_channel_tx, server)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(&recieved_parsed);
|
||||||
|
|
||||||
|
let source = unwrap_or_return_option!(&recieved_parsed.source);
|
||||||
|
|
||||||
|
if recieved_parsed.params[1] == "START_MESSAGE" {
|
||||||
|
let sender = unwrap_or_return_option!(helpers::get_nick(source));
|
||||||
|
|
||||||
|
let message = helpers::recieve_message_base64(
|
||||||
|
writer_channel_rx,
|
||||||
|
listener_channel_tx,
|
||||||
|
server,
|
||||||
|
"127.0.0.1",
|
||||||
|
&sender,
|
||||||
|
"END_MESSAGE",
|
||||||
|
)?; // Get
|
||||||
|
let message = encryption::decrypt(secret_key, &message, passwd)?; // Decrypt
|
||||||
|
|
||||||
|
listener_channel_tx.send(recieved.replace("START_MESSAGE", &message))?; // Send
|
||||||
|
} else if recieved_parsed.params[1] == "START_KEY" {
|
||||||
|
let sender = unwrap_or_return_option!(helpers::get_nick(source));
|
||||||
|
let to_send = helpers::bytes_to_privmsg_base64(public_key, &sender);
|
||||||
|
writer_channel_tx.send(to_send)?;
|
||||||
|
writer_channel_tx.send(format!("PRIVMSG {sender} END_KEY\r\n"))?;
|
||||||
|
|
||||||
|
let foreign_key = helpers::recieve_message_base64(
|
||||||
|
writer_channel_rx,
|
||||||
|
listener_channel_tx,
|
||||||
|
server,
|
||||||
|
"127.0.0.1",
|
||||||
|
&sender,
|
||||||
|
"END_KEY",
|
||||||
|
)?;
|
||||||
|
dbg!(&foreign_key);
|
||||||
|
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
|
||||||
|
println!("Got a key from {sender}");
|
||||||
|
keys.insert(sender.to_string(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -2,55 +2,72 @@ use openssl::ssl::{SslConnector, SslMethod};
|
||||||
use std::io::{ErrorKind, Write};
|
use std::io::{ErrorKind, Write};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
pub fn write_to_server(
|
pub fn write_to_server(
|
||||||
tcp_stream: TcpStream,
|
server: &str,
|
||||||
server: String,
|
port: &str,
|
||||||
rx: mpsc::Receiver<String>,
|
rx: mpsc::Receiver<String>,
|
||||||
tx: mpsc::Sender<String>,
|
tx: mpsc::Sender<String>,
|
||||||
) {
|
) {
|
||||||
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
|
'big: loop {
|
||||||
let mut stream = connector
|
println!("Connecting to {server}:{port}");
|
||||||
.connect(&server, tcp_stream)
|
let tcp_stream =
|
||||||
.expect("Couldn't start TLS");
|
TcpStream::connect(format!("{server}:{port}")).expect("Couldn't connect to server");
|
||||||
|
|
||||||
stream
|
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
|
||||||
.get_mut()
|
let mut stream = connector
|
||||||
.set_nonblocking(true)
|
.connect(server, &tcp_stream)
|
||||||
.expect("Failed to set nonblocking");
|
.expect("Couldn't start TLS");
|
||||||
|
|
||||||
loop {
|
stream
|
||||||
let mut buffer: Vec<u8> = Vec::new();
|
.get_mut()
|
||||||
let mut buf: [u8; 1] = [0];
|
.set_nonblocking(true)
|
||||||
let newline: u8 = b'\n';
|
.expect("Failed to set nonblocking");
|
||||||
|
|
||||||
while buf[0] != newline {
|
loop {
|
||||||
match stream.ssl_read(&mut buf) {
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
Ok(_length) => {
|
let mut buf: [u8; 1] = [0];
|
||||||
if _length > 0 {
|
let newline: u8 = b'\n';
|
||||||
buffer.push(buf[0]);
|
|
||||||
}
|
while buf[0] != newline {
|
||||||
}
|
match stream.ssl_read(&mut buf) {
|
||||||
Err(_error) => match _error.io_error() {
|
Ok(_length) => {
|
||||||
None => {
|
if _length > 0 {
|
||||||
dbg!(_error);
|
buffer.push(buf[0]);
|
||||||
}
|
|
||||||
Some(error) => match error.kind() {
|
|
||||||
ErrorKind::WouldBlock => {}
|
|
||||||
_ => {
|
|
||||||
dbg!(error.kind());
|
|
||||||
println!("Couldn't read the stream");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Err(_error) => match _error.io_error() {
|
||||||
|
None => {
|
||||||
|
dbg!(_error.ssl_error());
|
||||||
|
continue 'big;
|
||||||
|
}
|
||||||
|
Some(error) => match error.kind() {
|
||||||
|
ErrorKind::WouldBlock => {}
|
||||||
|
_ => {
|
||||||
|
dbg!(error.kind());
|
||||||
|
println!("Couldn't read the stream");
|
||||||
|
continue 'big;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
let value = rx.try_recv().unwrap_or("".to_string());
|
||||||
|
match value.as_str() {
|
||||||
|
"DUMMY CLOSE_CONNECTION" => {
|
||||||
|
continue 'big;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
match stream.write_all(value.as_bytes()) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_e) => println!("Couldn't send {value}"),
|
||||||
|
};
|
||||||
|
thread::sleep(Duration::from_micros(100));
|
||||||
}
|
}
|
||||||
let value = rx.try_recv().unwrap_or("".to_string());
|
|
||||||
match stream.write_all(value.as_bytes()) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(_e) => println!("Couldn't send {value}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = tx.send(dbg!(String::from_utf8_lossy(&buffer).to_string()));
|
let _ = tx.send(dbg!(String::from_utf8_lossy(&buffer).to_string()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue