1#[cfg(feature = "server")]
21pub mod server;
22
23#[cfg(feature = "client")]
24pub mod client;
25
26pub mod voice;
27
28use std::
29{
30 str::FromStr,
31 net::TcpStream,
32 mem::MaybeUninit,
33 io::{ Read, Write },
34 fmt::
35 {
36 self,
37 Display,
38 Formatter,
39 },
40};
41
42use wincode::
43{
44 SchemaWrite,
45 SchemaRead,
46 TypeMeta,
47 WriteResult,
48 ReadResult,
49 error::ReadError,
50 io::
51 {
52 Writer,
53 Reader,
54 },
55};
56
57use colored::Color;
58
59use why2::consts;
60
61use crate::{ crypto, options };
62
63#[cfg(feature = "server")]
64use std::time::{ Instant, Duration };
65
66#[cfg(feature = "server")]
67use crate::config;
68
69#[derive(SchemaWrite, SchemaRead, PartialEq, Clone)]
71pub enum MessageCode {
73 KeyExchange, Rekey, Welcome, Disconnect, Username, PasswordL, PasswordR, Accept, Join, Leave, List, PrivateMessage, PrivateMessageBack, SpamWarning, RegisterDisabled, Version, Channel, Voice, ChannelJoin, ChannelLeave, VoiceClients, InvalidUsage, InvalidFeature, }
97
98#[derive(Clone)]
99pub struct SerColor(pub Color); #[derive(SchemaWrite, SchemaRead, Clone)]
102pub struct MessageColors {
104 pub username_color: Option<SerColor>, pub message_color: Option<SerColor>, }
107
108#[derive(SchemaWrite, SchemaRead, Clone)]
109pub struct MessagePacket {
111 pub text: Option<String>, pub username: Option<String>, pub id: Option<usize>, pub code: Option<MessageCode>, pub colors: MessageColors, pub seq: usize, }
118
119impl Default for MessagePacket {
122 fn default() -> Self
123 {
124 Self
125 {
126 text: None,
127 username: None,
128 id: None,
129 code: None,
130 colors: MessageColors
131 {
132 username_color: None,
133 message_color: None,
134 },
135 seq: 0,
136 }
137 }
138}
139
140impl Display for SerColor {
142 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result
143 {
144 let color_str = match self.0
145 {
146 Color::Black => "black",
147 Color::Red => "red",
148 Color::Green => "green",
149 Color::Yellow => "yellow",
150 Color::Blue => "blue",
151 Color::Magenta => "magenta",
152 Color::Cyan => "cyan",
153 Color::BrightBlack => "bright black",
154 Color::BrightRed => "bright red",
155 Color::BrightGreen => "bright green",
156 Color::BrightYellow => "bright yellow",
157 Color::BrightBlue => "bright blue",
158 Color::BrightMagenta => "bright magenta",
159 Color::BrightCyan => "bright cyan",
160 Color::BrightWhite => "bright white",
161
162 _ => "white",
163 };
164
165 write!(f, "{color_str}")
166 }
167}
168
169impl FromStr for SerColor {
171 type Err = ReadError;
172
173 fn from_str(s: &str) -> Result<Self, Self::Err> {
174 Color::from_str(s)
175 .map(SerColor)
176 .map_err(|_| ReadError::Custom("Invalid color string"))
177 }
178}
179
180impl SchemaWrite for SerColor
182{
183 type Src = Self;
184 const TYPE_META: TypeMeta = TypeMeta::Dynamic;
185
186 fn size_of(src: &Self::Src) -> WriteResult<usize>
187 {
188 <String as SchemaWrite>::size_of(&src.to_string())
189 }
190
191 fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()>
192 {
193 <String as SchemaWrite>::write(writer, &src.to_string())
194 }
195}
196
197impl<'de> SchemaRead<'de> for SerColor
199{
200 type Dst = Self;
201 const TYPE_META: TypeMeta = TypeMeta::Dynamic;
202
203 fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()>
204 {
205 dst.write(<String as SchemaRead>::get(reader)?.parse::<SerColor>()?);
206 Ok(())
207 }
208}
209
210fn obfuscate_data(data: &[u8]) -> Vec<u8> {
214 let mut obfuscated = data.to_vec();
215 for (i, byte) in obfuscated.iter_mut().enumerate()
216 {
217 *byte ^= options::OBFUSCATION_KEY[i % options::OBFUSCATION_KEY.len()];
219 }
220
221 obfuscated
222}
223
224pub fn send(stream: &mut TcpStream, mut packet: MessagePacket, keys: Option<&options::SharedKeys>) {
227 #[cfg(feature = "client")]
229 {
230 packet.seq = options::get_seq() + 1;
231 options::set_seq(packet.seq);
232 }
233
234 #[cfg(feature = "server")]
236 {
237 let peer_addr = stream.peer_addr().ok();
238 if peer_addr.is_some() && let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr.unwrap())
239 {
240 if conn.is_authenticated()
241 {
242 packet.seq = conn.server_seq().unwrap() + 1;
243 *conn.server_seq_mut().unwrap() = packet.seq;
244 }
245 }
246 }
247
248 let packet_bytes = wincode::serialize(&packet).expect("Encoding packet failed");
250
251 let mut final_bytes = if let Some(keys) = keys
252 {
253 crypto::encrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(packet_bytes, keys)
254 } else
255 {
256 obfuscate_data(&packet_bytes) };
258
259 let packet_len = final_bytes.len();
261 let mut transmission_packet = Vec::with_capacity(4 + packet_len);
262 transmission_packet.extend_from_slice(&(packet_len as u32).to_be_bytes());
263 transmission_packet.append(&mut final_bytes);
264
265 let _ = stream.write_all(&transmission_packet);
267 stream.flush().expect("Flushing stream failed");
268}
269
270pub fn receive(stream: &mut TcpStream, keys: Option<&options::SharedKeys>) -> Option<MessagePacket>
271{
272 #[cfg(feature = "server")]
274 let max_packet_size: usize;
275
276 #[cfg(feature = "server")]
278 let spam_protection = config::server_config::<bool>("spam_protection");
279
280 #[cfg(feature = "server")]
281 let peer_addr = stream.peer_addr().ok()?; #[cfg(feature = "server")]
285 {
286 let authenticated = server::CONNECTIONS.get(&peer_addr)
288 .map(|conn| conn.is_authenticated())
289 .unwrap_or(false);
290
291 max_packet_size = if !spam_protection && authenticated
293 {
294 usize::MAX
295 } else {
297 config::server_config("max_packet_size")
298 };
299 }
300
301 let mut len_buf = [0u8; 4];
303 if stream.read_exact(&mut len_buf).is_err() { return None; } let len = u32::from_be_bytes(len_buf) as usize;
305
306 #[cfg(feature = "server")]
308 if len > max_packet_size
309 {
310 server::remove_connection(&peer_addr, true);
311 return None;
312 }
313
314 let mut decoded_packet = vec![0u8; len];
316 if stream.read_exact(&mut decoded_packet).is_err() { return None; } if let Some(keys) = keys
320 {
321 decoded_packet = match crypto::decrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(decoded_packet, keys)
322 {
323 Some(d) => d,
324 None => {
326 #[cfg(feature = "server")]
328 log::warn!("HMAC verification failed: {}", peer_addr);
329
330 return None;
331 }
332 }
333 } else
334 {
335 decoded_packet = obfuscate_data(&decoded_packet); }
337
338 #[cfg(feature = "server")]
340 {
341 let mut spam_warning = false;
342 let mut shared_key = None;
343 let mut disconnect = false;
344
345 if let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr)
347 {
348 if config::server_config("spam_protection") && conn.is_authenticated() &&
350 Instant::now().duration_since(*conn.last_activity()) <
351 Duration::from_millis(config::server_config::<u64>("min_message_delay"))
352 {
353 *conn.spam_violations_mut().unwrap() += 1;
355
356 spam_warning = true;
358 shared_key = conn.keys().cloned();
359
360 disconnect = *conn.spam_violations().unwrap() > config::server_config::<usize>("max_message_delay_violations");
362 }
363
364 *conn.last_activity_mut() = Instant::now(); }
366
367 if spam_warning
369 {
370 server::send_code(stream, None, MessageCode::SpamWarning, shared_key.as_ref());
371 }
372
373 if disconnect
375 {
376 server::remove_connection(&peer_addr, true);
377 return None;
378 }
379 }
380
381 match wincode::deserialize::<MessagePacket>(&decoded_packet)
383 {
384 Ok(packet) =>
385 {
386 #[cfg(feature = "server")] {
389 if let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr)
390 {
391 if packet.seq > *conn.seq() {
393 *conn.seq_mut() = packet.seq;
395 } else
396 {
397 drop(conn); log::warn!("SEQ verification failed: {}", &peer_addr);
400 server::remove_connection(&peer_addr, false);
401 }
402 }
403 }
404
405 #[cfg(feature = "client")] {
408 if packet.seq > options::get_server_seq() || options::get_server_seq() == 0 || packet.code == Some(MessageCode::Disconnect) {
410 options::set_server_seq(packet.seq);
412 } else {
414 return None;
415 }
416 }
417
418 return Some(packet);
419 },
420
421 Err(_) =>
422 {
423 #[cfg(feature = "server")]
425 server::remove_connection(&peer_addr, false);
426
427 return None;
428 }
429 }
430}