#[cfg(feature = "server")]
pub mod server;
#[cfg(feature = "client_base")]
pub mod client;
pub mod file;
#[cfg(any(feature = "server", feature = "client_screen"))]
pub mod screen;
#[cfg(any(feature = "server", feature = "client_voice"))]
pub mod voice;
use std::
{
net::TcpStream,
io::{ Read, Write },
};
use wincode::
{
config::DefaultConfig,
SchemaWrite,
SchemaRead,
};
use zeroize::Zeroizing;
use why2::
{
consts,
stream::RexStream,
};
use crate::
{
crypto,
consts::
{
Streams,
self as chat_consts,
},
};
#[cfg(feature = "client_base")]
use crate::options;
#[cfg(feature = "server")]
use std::
{
net::SocketAddr,
time::{ Instant, Duration },
};
#[cfg(feature = "server")]
use crate::config;
pub trait SequencedPacket: SchemaWrite<DefaultConfig, Src = Self>
{
fn seq(&self) -> usize;
fn set_seq(&mut self, seq: usize);
}
#[derive(SchemaWrite, SchemaRead, PartialEq, Clone)]
pub enum MessageCode {
KeyExchange, Rekey, Welcome, Disconnect, Username, PasswordL, PasswordR, Accept, Join, Leave, List, PrivateMessage, PrivateMessageBack, SpamWarning, RegisterDisabled, Version, Channel, Voice, ChannelJoin, ChannelLeave, VoiceClients, Upload, Download, Uploaded, Files, Screens, Attach, Deattach, UploadLimit, Screen, InvalidUsage, InvalidFeature, KeepAlive, }
pub enum EncryptionMode<'a> {
OneShot(Option<&'a chat_consts::SharedKeys>), Stream(&'a mut RexStream), }
#[derive(SchemaWrite, SchemaRead, Clone, Default)]
pub struct MessageColors {
pub username_color: Option<u8>, pub message_color: Option<u8>, }
#[derive(SchemaWrite, SchemaRead, Clone, Default)]
pub struct MessagePacket {
pub text: Option<String>, pub username: Option<String>, pub id: Option<usize>, pub code: Option<MessageCode>, pub colors: MessageColors, pub seq: usize, pub token: Option<[u8; 32]>, }
pub struct ReadResult {
#[cfg(feature = "server")] pub peer_addr: SocketAddr,
pub data: Zeroizing<Vec<u8>>,
}
impl SequencedPacket for MessagePacket
{
fn seq(&self) -> usize { self.seq }
fn set_seq(&mut self, seq: usize) { self.seq = seq; }
}
fn obfuscate_data(data: &[u8], obfuscation_key: [u8; 32]) -> Vec<u8> {
let mut result = Vec::with_capacity(data.len());
for (i, byte) in data.iter().enumerate()
{
result.push(*byte ^ obfuscation_key[i % obfuscation_key.len()]);
}
result
}
pub fn send_tcp (
stream: &mut TcpStream,
mut packet: impl SequencedPacket,
encryption_mode: EncryptionMode,
seq: Option<&mut usize>, )
{
#[cfg(feature = "client_base")]
{
match seq
{
Some(local_seq) =>
{
*local_seq += 1;
packet.set_seq(*local_seq);
},
None =>
{
packet.set_seq(options::get_seq() + 1);
options::set_seq(packet.seq());
}
}
}
#[cfg(feature = "server")]
{
match seq
{
Some(local_seq) =>
{
*local_seq += 1;
packet.set_seq(*local_seq);
},
None =>
{
let peer_addr = stream.peer_addr().ok();
if peer_addr.is_some() && let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr.unwrap())
{
if conn.is_authenticated()
{
packet.set_seq(conn.server_seq().unwrap() + 1);
*conn.server_seq_mut().unwrap() = packet.seq();
}
}
}
}
}
let packet_bytes = Zeroizing::new(wincode::serialize(&packet).expect("Encoding packet failed"));
let mut final_bytes = match encryption_mode
{
EncryptionMode::OneShot(Some(keys)) =>
{
crypto::encrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(&packet_bytes, keys)
},
EncryptionMode::OneShot(None) =>
{
let key =
{
#[cfg(feature = "server")]
{
stream.peer_addr().ok()
.and_then(|addr| server::CONNECTIONS.get(&addr))
.and_then(|c| c.obfuscation_key().cloned())
.unwrap_or_else(|| [0u8; 32])
}
#[cfg(feature = "client_base")]
{
options::get_obfuscation_key()
}
};
obfuscate_data(&packet_bytes, key) },
EncryptionMode::Stream(rex_stream) =>
{
let input_i64 = Zeroizing::new(crypto::bytes_to_i64(&packet_bytes));
let mut encrypted_i64 = Zeroizing::new(rex_stream.update(&input_i64).expect("Stream encryption failed"));
encrypted_i64.extend(rex_stream.finalize().expect("Stream finalize failed"));
let mut final_bytes = crypto::i64_to_bytes(&encrypted_i64);
final_bytes.truncate(packet_bytes.len());
final_bytes
},
};
let packet_len = final_bytes.len();
let mut transmission_packet = Vec::with_capacity(4 + packet_len);
transmission_packet.extend_from_slice(&(packet_len as u32).to_be_bytes());
transmission_packet.append(&mut final_bytes);
if stream.write_all(&transmission_packet).is_ok()
{
stream.flush().ok();
}
}
pub fn read_tcp
(
streams: &mut Streams,
encryption_mode: EncryptionMode,
#[cfg(feature = "server")] auxiliary: bool,
) -> Option<ReadResult>
{
#[cfg(feature = "server")]
let max_packet_size: usize;
#[cfg(feature = "server")]
let spam_protection = config::read_config::<bool>("spam_protection");
#[cfg(feature = "server")]
let peer_addr = streams.0.peer_addr().ok()?;
#[cfg(feature = "server")]
{
let authenticated = server::CONNECTIONS.get(&peer_addr)
.map(|conn| conn.is_authenticated())
.unwrap_or(false);
max_packet_size = if (!spam_protection && authenticated) || auxiliary
{
usize::MAX
} else {
config::read_config("max_packet_size")
};
}
let mut len_buf = [0u8; 4];
if streams.0.read_exact(&mut len_buf).is_err() {
#[cfg(feature = "server")]
server::remove_connection(&peer_addr, false, Some("length"));
return None;
}
let len = u32::from_be_bytes(len_buf) as usize;
#[cfg(feature = "server")]
if len > max_packet_size
{
server::remove_connection(&peer_addr, true, Some("length"));
return None;
}
let mut decoded_packet = Zeroizing::new(vec![0u8; len]);
if streams.0.read_exact(&mut decoded_packet).is_err() {
#[cfg(feature = "server")]
server::remove_connection(&peer_addr, false, Some("length"));
return None;
}
decoded_packet = match encryption_mode
{
EncryptionMode::OneShot(Some(keys)) =>
{
match crypto::decrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(decoded_packet.to_vec(), keys)
{
Some(d) => d,
None => {
#[cfg(feature = "server")]
log::warn!("HMAC verification failed: {}", peer_addr);
return None;
}
}
},
EncryptionMode::OneShot(None) =>
{
let key =
{
#[cfg(feature = "server")]
{
server::CONNECTIONS.get(&peer_addr)
.and_then(|c| c.obfuscation_key().cloned())
.unwrap_or_else(|| [0u8; 32])
}
#[cfg(feature = "client_base")]
{
options::get_obfuscation_key()
}
};
Zeroizing::new(obfuscate_data(&decoded_packet, key)) },
EncryptionMode::Stream(rex_stream) =>
{
let original_len = decoded_packet.len();
let input_i64 = Zeroizing::new(crypto::bytes_to_i64(&decoded_packet));
let mut decrypted_i64 = Zeroizing::new(rex_stream.update(&input_i64).expect("Stream decryption failed"));
decrypted_i64.extend(rex_stream.finalize().expect("Stream finalize failed"));
let mut output_bytes = Zeroizing::new(crypto::i64_to_bytes(&decrypted_i64));
output_bytes.truncate(original_len);
output_bytes
}
};
Some(ReadResult
{
#[cfg(feature = "server")] peer_addr,
data: decoded_packet,
})
}
pub fn send (
stream: &mut TcpStream,
packet: MessagePacket,
keys: Option<&chat_consts::SharedKeys>,
)
{
send_tcp
(
stream,
packet,
EncryptionMode::OneShot(keys),
None,
);
}
pub fn receive
(
streams: &mut Streams,
keys: Option<&chat_consts::SharedKeys>,
seq: Option<&mut usize> ) -> Option<MessagePacket>
{
let read = read_tcp
(
streams,
EncryptionMode::OneShot(keys),
#[cfg(feature = "server")] false,
)?;
match wincode::deserialize::<MessagePacket>(&read.data)
{
Ok(packet) =>
{
#[cfg(feature = "server")]
{
if let Some(seq) = seq
{
if packet.seq > *seq {
*seq = packet.seq;
} else { return None; }
} else if let Some(mut conn) = server::CONNECTIONS.get_mut(&read.peer_addr)
{
let mut spam_warning = false;
let mut shared_key = None;
let mut disconnect = false;
let mut grace = true;
if packet.code != Some(MessageCode::KeepAlive) &&
packet.code != Some(MessageCode::KeyExchange)
{
if let Some(text) = &packet.text && conn.is_authenticated()
{
disconnect = text.len() > config::read_config("max_message_length");
}
if !disconnect && config::read_config("spam_protection") && conn.is_authenticated() &&
Instant::now().duration_since(*conn.last_activity()) <
Duration::from_millis(config::read_config::<u64>("min_message_delay"))
{
*conn.spam_violations_mut().unwrap() += 1;
spam_warning = true;
shared_key = conn.keys().cloned();
disconnect = *conn.spam_violations().unwrap() > config::read_config::<usize>("max_message_delay_violations");
}
*conn.last_activity_mut() = Instant::now(); }
if packet.seq > *conn.seq() {
*conn.seq_mut() = packet.seq;
} else
{
grace = false;
disconnect = true;
}
drop(conn);
if spam_warning
{
server::send_code(&mut streams.1.lock().unwrap(), None, MessageCode::SpamWarning, shared_key.as_ref());
}
if disconnect
{
server::remove_connection(&read.peer_addr, grace, Some(if !grace { "SEQ" } else { "SPAM" }));
return None;
}
}
}
#[cfg(feature = "client_base")] {
let used_seq = match seq
{
Some(ref s) => **s,
None => options::get_server_seq(),
};
if packet.seq > used_seq || used_seq == 0 || packet.code == Some(MessageCode::Disconnect) {
if let Some(seq) = seq
{
*seq = packet.seq;
} else
{
options::set_server_seq(packet.seq);
}
} else {
return None;
}
}
return Some(packet);
},
Err(_) =>
{
#[cfg(feature = "server")]
server::remove_connection(&read.peer_addr, false, Some("packet"));
return None;
}
}
}