1#[cfg(feature = "server")]
21pub mod server;
22
23#[cfg(feature = "client")]
24pub mod client;
25
26pub mod voice;
27
28use std::
29{
30 fs::File,
31 path::PathBuf,
32 net::TcpStream,
33 io::{ Read, Write },
34};
35
36use wincode::{ SchemaWrite, SchemaRead };
37
38use why2::consts;
39
40use crate::
41{
42 crypto,
43 consts::
44 {
45 Streams,
46 self as chat_consts,
47 },
48};
49
50#[cfg(feature = "client")]
51use crate::options;
52
53#[cfg(feature = "server")]
54use std::time::{ Instant, Duration };
55
56#[cfg(feature = "server")]
57use crate::config;
58
59#[derive(SchemaWrite, SchemaRead, PartialEq, Clone)]
61pub enum MessageCode {
63 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, UploadLimit, InvalidUsage, InvalidFeature, KeepAlive, }
93
94#[derive(SchemaWrite, SchemaRead, Clone)]
96pub struct MessageColors {
98 pub username_color: Option<u8>, pub message_color: Option<u8>, }
101
102#[derive(SchemaWrite, SchemaRead, Clone)]
103pub struct FilePayload {
105 pub token: Option<[u8; 32]>, pub uid: u64, pub data: Option<Vec<u8>>, pub size: Option<u64>, pub filename: Option<String>, pub hash: Option<[u8; 32]>, }
112
113#[derive(SchemaWrite, SchemaRead, Clone)]
114pub struct MessagePacket {
116 pub text: Option<String>, pub username: Option<String>, pub id: Option<usize>, pub code: Option<MessageCode>, pub colors: MessageColors, pub seq: usize, pub file: Option<FilePayload>, }
124
125impl Default for MessagePacket {
128 fn default() -> Self
129 {
130 Self
131 {
132 text: None,
133 username: None,
134 id: None,
135 code: None,
136 colors: MessageColors
137 {
138 username_color: None,
139 message_color: None,
140 },
141 seq: 0,
142 file: None,
143 }
144 }
145}
146
147impl Default for FilePayload
148{
149 fn default() -> Self
150 {
151 Self
152 {
153 token: None,
154 uid: 0,
155 data: None,
156 size: None,
157 filename: None,
158 hash: None,
159 }
160 }
161}
162
163fn obfuscate_data(mut data: Vec<u8>, obfuscation_key: [u8; 32]) -> Vec<u8> {
167 for (i, byte) in data.iter_mut().enumerate()
168 {
169 *byte ^= obfuscation_key[i % obfuscation_key.len()];
171 }
172
173 data
174}
175
176pub fn send (
179 stream: &mut TcpStream,
180 mut packet: MessagePacket,
181 keys: Option<&chat_consts::SharedKeys>,
182 #[cfg(feature = "server")] seq: Option<&mut usize>, )
184{
185 #[cfg(feature = "client")]
187 {
188 packet.seq = options::get_seq() + 1;
189 options::set_seq(packet.seq);
190 }
191
192 #[cfg(feature = "server")]
194 {
195 match seq
196 {
197 Some(local_seq) =>
198 {
199 *local_seq += 1;
200 packet.seq = *local_seq;
201 },
202
203 None =>
204 {
205 let peer_addr = stream.peer_addr().ok();
206 if peer_addr.is_some() && let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr.unwrap())
207 {
208 if conn.is_authenticated()
209 {
210 packet.seq = conn.server_seq().unwrap() + 1;
211 *conn.server_seq_mut().unwrap() = packet.seq;
212 }
213 }
214 }
215 }
216 }
217
218 let packet_bytes = wincode::serialize(&packet).expect("Encoding packet failed");
220
221 let mut final_bytes = if let Some(keys) = keys
222 {
223 crypto::encrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(packet_bytes, keys)
224 } else
225 {
226 let key =
227 {
228 #[cfg(feature = "server")]
229 {
230 stream.peer_addr().ok()
231 .and_then(|addr| server::CONNECTIONS.get(&addr))
232 .and_then(|c| c.obfuscation_key().cloned())
233 .unwrap_or_else(|| [0u8; 32])
234 }
235
236 #[cfg(feature = "client")]
237 {
238 options::get_obfuscation_key()
239 }
240 };
241
242 obfuscate_data(packet_bytes, key) };
244
245 let packet_len = final_bytes.len();
247 let mut transmission_packet = Vec::with_capacity(4 + packet_len);
248 transmission_packet.extend_from_slice(&(packet_len as u32).to_be_bytes());
249 transmission_packet.append(&mut final_bytes);
250
251 let _ = stream.write_all(&transmission_packet);
253 stream.flush().expect("Flushing stream failed");
254}
255
256pub fn receive
257(
258 streams: &mut Streams,
259 keys: Option<&chat_consts::SharedKeys>,
260 seq: Option<&mut usize> ) -> Option<MessagePacket>
262{
263 #[cfg(feature = "server")]
265 let max_packet_size: usize;
266
267 #[cfg(feature = "server")]
269 let spam_protection = config::read_config::<bool>("spam_protection");
270
271 #[cfg(feature = "server")]
272 let peer_addr = streams.0.peer_addr().ok()?; #[cfg(feature = "server")]
276 {
277 let authenticated = server::CONNECTIONS.get(&peer_addr)
279 .map(|conn| conn.is_authenticated())
280 .unwrap_or(false);
281
282 max_packet_size = if !spam_protection && authenticated
284 {
285 usize::MAX
286 } else {
288 config::read_config("max_packet_size")
289 };
290 }
291
292 let mut len_buf = [0u8; 4];
294 if streams.0.read_exact(&mut len_buf).is_err() {
296 #[cfg(feature = "server")]
297 server::remove_connection(&peer_addr, false, Some("length"));
298 return None;
299 }
300 let len = u32::from_be_bytes(len_buf) as usize;
301
302 #[cfg(feature = "server")]
304 if len > max_packet_size
305 {
306 server::remove_connection(&peer_addr, true, Some("length"));
307 return None;
308 }
309
310 let mut decoded_packet = vec![0u8; len];
312 if streams.0.read_exact(&mut decoded_packet).is_err() {
314 #[cfg(feature = "server")]
315 server::remove_connection(&peer_addr, false, Some("length"));
316 return None;
317 }
318
319 if let Some(keys) = keys
321 {
322 decoded_packet = match crypto::decrypt_packet::<{ consts::DEFAULT_GRID_WIDTH }, { consts::DEFAULT_GRID_HEIGHT }>(decoded_packet, keys)
323 {
324 Some(d) => d,
325 None => {
327 #[cfg(feature = "server")]
329 log::warn!("HMAC verification failed: {}", peer_addr);
330
331 return None;
332 }
333 }
334 } else
335 {
336 let key =
337 {
338 #[cfg(feature = "server")]
339 {
340 server::CONNECTIONS.get(&peer_addr)
341 .and_then(|c| c.obfuscation_key().cloned())
342 .unwrap_or_else(|| [0u8; 32])
343 }
344
345 #[cfg(feature = "client")]
346 {
347 options::get_obfuscation_key()
348 }
349 };
350
351 decoded_packet = obfuscate_data(decoded_packet, key); }
353
354 match wincode::deserialize::<MessagePacket>(&decoded_packet)
356 {
357 Ok(packet) =>
358 {
359 #[cfg(feature = "server")]
361 {
362 if let Some(seq) = seq
364 {
365 if packet.seq > *seq {
367 *seq = packet.seq;
369 } else { return None; }
370 } else if let Some(mut conn) = server::CONNECTIONS.get_mut(&peer_addr)
371 {
372 let mut spam_warning = false;
374 let mut shared_key = None;
375 let mut disconnect = false;
376 let mut grace = true;
377
378 if packet.code != Some(MessageCode::KeepAlive) &&
380 packet.code != Some(MessageCode::KeyExchange) &&
381 packet.file.is_none()
382 {
383 if let Some(text) = &packet.text && conn.is_authenticated()
385 {
386 disconnect = text.len() > config::read_config("max_message_length");
387 }
388
389 if !disconnect && config::read_config("spam_protection") && conn.is_authenticated() &&
390 Instant::now().duration_since(*conn.last_activity()) <
391 Duration::from_millis(config::read_config::<u64>("min_message_delay"))
392 {
393 *conn.spam_violations_mut().unwrap() += 1;
395
396 spam_warning = true;
398 shared_key = conn.keys().cloned();
399
400 disconnect = *conn.spam_violations().unwrap() > config::read_config::<usize>("max_message_delay_violations");
402 }
403
404 *conn.last_activity_mut() = Instant::now(); }
406
407 if packet.seq > *conn.seq() {
410 *conn.seq_mut() = packet.seq;
412 } else
413 {
414 grace = false;
416 disconnect = true;
417 }
418 drop(conn); if spam_warning
422 {
423 server::send_code(&mut streams.1.lock().unwrap(), None, MessageCode::SpamWarning, shared_key.as_ref());
424 }
425
426 if disconnect
428 {
429 server::remove_connection(&peer_addr, grace, Some(if !grace { "SEQ" } else { "SPAM" }));
430 return None;
431 }
432 }
433 }
434
435 #[cfg(feature = "client")] {
438 let used_seq = match seq
439 {
440 Some(ref s) => **s,
441 None => options::get_server_seq(),
442 };
443
444 if packet.seq > used_seq || used_seq == 0 || packet.code == Some(MessageCode::Disconnect) {
446 if let Some(seq) = seq
448 {
449 *seq = packet.seq;
450 } else
451 {
452 options::set_server_seq(packet.seq);
453 }
454 } else {
456 return None;
457 }
458 }
459
460 return Some(packet);
461 },
462
463 Err(_) =>
464 {
465 #[cfg(feature = "server")]
467 server::remove_connection(&peer_addr, false, Some("packet"));
468
469 return None;
470 }
471 }
472}
473
474pub fn send_file (
476 path: PathBuf,
477 mut stream: TcpStream,
478 uid: u64,
479 code: MessageCode,
480 keys: Option<&chat_consts::SharedKeys>,
481)
482{
483 let mut file = File::open(path).expect("Cannot open file for upload");
484 let mut buffer = vec![0; chat_consts::UPLOAD_CHUNK_SIZE];
485
486 #[cfg(feature = "server")]
487 let mut seq = 0usize;
488
489 loop
491 {
492 match file.read(&mut buffer)
493 {
494 Ok(0) => break, Ok(bytes) =>
496 {
497 send(&mut stream, MessagePacket
499 {
500 code: Some(code.clone()),
501 file: Some(FilePayload
502 {
503 uid,
504 data: Some(buffer[..bytes].to_vec()),
505 ..Default::default()
506 }),
507 ..Default::default()
508 }, keys, #[cfg(feature = "server")] Some(&mut seq));
509 },
510 Err(_) => {}, }
512 }
513}