use hashbrown::HashSet; use integer_encoding::{FixedInt, VarInt}; use secretbox::CipherType::Salsa20; use secretbox::SecretBox; use serde::Serialize; use std::io::{Error, Read, Write}; use std::net::{Shutdown, TcpStream}; /// Connections provides an interface for manage sets of connections on top of a particular /// ACN. pub mod service; #[derive(Debug)] pub enum ServiceError { ClosedNormally, ConnectionFailed(String), ListenFailed(String), } #[derive(Clone)] pub struct InboundConnection(()); #[derive(Clone)] pub struct OutboundConnection(()); #[derive(Clone, Eq, PartialEq, Hash)] pub struct Capability(pub &'static str); pub struct Connection { conn: TcpStream, direction: Direction, key: Vec, hostname: String, capabilities: HashSet, } pub trait ConnectionInterface { fn set_hostname(&mut self, hostname: &String); fn hostname(&self) -> String; fn enable_encryption(&mut self, key: Vec); fn send(&mut self, amsg: &String) -> Result<(), Error>; fn send_encrypted(&mut self, msg: Vec) -> Result<(), Error>; fn expect_encrypted(&mut self) -> Vec; fn expect(&mut self) -> Result, Error>; fn shutdown(&mut self); fn set_capability(&mut self, capability: &Capability); fn has_capability(&self, capability: &Capability) -> bool; } impl ConnectionInterface for Connection { fn set_hostname(&mut self, hostname: &String) { self.hostname = hostname.clone() } fn hostname(&self) -> String { self.hostname.clone() } fn enable_encryption(&mut self, key: Vec) { self.key = key } fn send(&mut self, amsg: &String) -> Result<(), Error> { let mut len = [0u8; 2]; (amsg.len() as u16).encode_var(&mut len); let mut msg = vec![]; msg.extend_from_slice(len.as_slice()); msg.extend_from_slice(amsg.as_bytes()); let mut msg = msg; while msg.len() < 8192 { msg.push(0); } self.conn.write_all(msg.as_slice()) } fn send_encrypted(&mut self, msg: Vec) -> Result<(), Error> { let mut msg = msg; while msg.len() < 8192 - 40 { msg.push(0); } let secret_box = SecretBox::new(&self.key, Salsa20).unwrap(); let msg = secret_box.easy_seal(msg.as_slice()); self.conn.write_all(msg.as_slice()) } fn expect_encrypted(&mut self) -> Vec { let secret_box = SecretBox::new(&self.key, Salsa20).unwrap(); let mut result = [0u8; 8192]; match self.conn.read_exact(&mut result) { Err(_e) => { return vec![]; } _ => {} } let msg = match secret_box.easy_unseal(&result) { Some(msg) => msg, _ => { return vec![]; } }; let msg = msg.as_slice(); let _len_bytes = [0u8; 2]; let len = u16::decode_fixed(&msg[0..2]) as usize; if len > 8192 { return vec![]; // lol no. } msg[2..len + 2].to_vec() } fn expect(&mut self) -> Result, Error> { let mut msg = [0; 8192]; let result = self.conn.read_exact(&mut msg); match result { Err(e) => Err(e), Ok(()) => { // TODO why did I decide to use varints here?!?! let len = u16::decode_var(&msg[0..2]).unwrap().0 as usize; // println!("{} [{}]", len, String::from_utf8(msg[2..len + 2].to_vec()).unwrap()); return Ok(msg[2..len + 2].to_vec()); } } } fn shutdown(&mut self) { match self.conn.shutdown(Shutdown::Both) { _ => {} // If anything bad happens we will know soon enough... } } fn set_capability(&mut self, capability: &Capability) { self.capabilities.insert(capability.clone()); } fn has_capability(&self, capability: &Capability) -> bool { self.capabilities.contains(capability) } } impl Connection where Direction: Clone, { pub fn new_inbound(conn: TcpStream) -> Connection { Connection { conn, direction: InboundConnection(()), key: vec![], hostname: String::new(), capabilities: HashSet::new(), } } pub fn new_outbound(conn: TcpStream) -> Connection { Connection { conn, direction: OutboundConnection(()), key: vec![], hostname: String::new(), capabilities: HashSet::new(), } } /// Send anything implemented Serialize as JSON pub fn send_json_encrypted(&mut self, data: T) -> Result<(), Error> where T: Serialize, { let mut msg = vec![]; let mut len = [0u8; 2]; let json = serde_json::to_string(&data).unwrap(); (json.len() as u16).encode_fixed(&mut len); msg.extend_from_slice(len.as_slice()); msg.extend_from_slice(json.as_bytes()); self.send_encrypted(msg) } pub fn try_clone(&self) -> Connection { Connection { conn: self.conn.try_clone().unwrap(), direction: self.direction.clone(), key: self.key.clone(), hostname: self.hostname.clone(), capabilities: self.capabilities.clone(), } } } pub struct Hostname {}