1use std::
20{
21 thread,
22 io::Write,
23 collections::HashMap,
24 fs::{ self, File },
25 path::{ Path, PathBuf },
26 sync::
27 {
28 Arc,
29 Mutex,
30 LazyLock,
31 mpsc::Sender,
32 },
33};
34
35use sha2::{ Sha256, Digest };
36
37use zeroize::Zeroizing;
38
39use serde_json::Value;
40
41use semver::Version;
42
43use crate::
44{
45 options,
46 misc,
47 crypto::kex,
48 consts::{ self, Streams },
49 config::{ self, TofuCode },
50 network::
51 {
52 self,
53 MessageCode,
54 MessagePacket,
55 ActiveFileshare,
56 voice::
57 {
58 client as voice_client,
59 options as voice_options,
60 }
61 },
62};
63
64pub struct VoiceUser
66{
67 pub id: usize, pub username: String, pub is_speaking: bool, pub latency: u128, pub is_local: bool, }
73
74pub enum ClientEvent
76{
77 Register, Login, Authenticated, Connected(String), Message(MessagePacket), Prompt(String, String), PrivateMessageSent(String, usize, String), PrivateMessageRecv(String, usize, String), TofuError(TofuCode), VoiceActivity(Vec<VoiceUser>), Join(String), Leave(String), Clear(usize), InvalidUsage, VersionFailed, UnsafeVersion(usize, Version, String), Username(bool, u64, u64), VoiceEnabled, VoiceDisabled, List(Value), Upload(String), Uploaded(String, String), Download(String), Downloaded(String), DownloadFailed(String), Files(Vec<Value>), ExtraSpace, IncompatibleVersion(String, String), UsernameRejected, PasswordRejected(u64), SpamWarning, Socks5Voice, DisabledFeature, Quit, }
112
113pub static ACTIVE_UPLOADS: LazyLock<Arc<Mutex<HashMap<[u8; 32], PathBuf>>>> = LazyLock::new(|| {
116 Arc::new(Mutex::new(HashMap::new()))
117});
118
119fn key_exchange
122(
123 streams: &mut Streams,
124 keys: &mut consts::SharedKeys,
125 tx: &Sender<ClientEvent>
126) -> bool {
128 let message = loop
130 {
131 let received = network::receive(streams, None).unwrap();
133
134 if received.code == Some(MessageCode::KeyExchange) { break received; }
135 };
136
137 let message_text = message.text.as_ref().unwrap();
138
139 let server_keys: Value = serde_json::from_str(message_text).expect("Failed to parse server keys JSON");
141 let server_ecc_pk = server_keys["ecc"].as_str().expect("Parsing server ECC key failed");
142 let server_pq_pk = server_keys["pq"].as_str().expect("Parsing server PQ key failed");
143
144 match config::server_keys_check(&streams.0.peer_addr().unwrap().ip().to_string(), message_text)
146 {
147 TofuCode::Valid => {},
148
149 status @ (TofuCode::Mismatch | TofuCode::Unknown(_, _)) =>
150 {
151 network::send(&mut streams.1.lock().unwrap(), MessagePacket
153 {
154 code: Some(MessageCode::Disconnect),
155 ..Default::default()
156 }, None);
157
158 tx.send(ClientEvent::TofuError(status)).unwrap();
160
161 return false;
163 },
164 }
165
166 let (sk, pk) = kex::generate_ephemeral_keys();
168
169 let (pq_ciphertext, pq_secret) = kex::encapsulate_pq(server_pq_pk);
171
172 let response_text = serde_json::json!
174 ({
175 "ecc": pk,
176 "pq": pq_ciphertext,
177 }).to_string();
178
179 network::send(&mut streams.1.lock().unwrap(), MessagePacket
181 {
182 text: Some(response_text),
183 code: Some(MessageCode::KeyExchange),
184 ..Default::default()
185 }, None);
186
187 *keys = kex::derive_shared_secret(sk, server_ecc_pk.to_string(), pq_secret).expect("Shared secret derivation failed");
189
190 options::set_keys(keys.clone());
192
193 true
194}
195
196pub fn listen_server(streams: &mut Streams, tx: Sender<ClientEvent>) {
199 let mut keys = (Zeroizing::new(vec![]), Zeroizing::new(vec![]));
201 if !key_exchange(streams, &mut keys, &tx) { return; }
202
203 let mut min_pass: Option<u64> = None;
205 let mut max_uname: Option<u64> = None;
206 let mut min_uname: Option<u64> = None;
207
208 let mut invalid_username = false; let mut invalid_password = false;
210
211 let mut disabled_registration = false; let mut first_message = true;
215 let mut extra_space: bool;
216
217 let mut channel = String::new();
218
219 let mut id = 0usize; let mut username: Option<String> = None;
222
223 loop
225 {
226 let read = match network::receive(streams, Some(&keys))
227 {
228 Some(packet) => packet,
229 None => MessagePacket
230 {
231 code: Some(MessageCode::Disconnect),
232 ..Default::default()
233 }
234 };
235
236 if options::is_muted(read.id) { continue; }
238
239 if read.code == Some(MessageCode::KeepAlive)
241 {
242 network::send(&mut streams.1.lock().unwrap(), MessagePacket
244 {
245 code: Some(MessageCode::KeepAlive),
246 ..Default::default()
247 }, options::get_keys().as_ref());
248 continue;
249 }
250
251 extra_space = false; if options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
255
256 if let Some(code) = read.code
258 {
259 match code
260 {
261 MessageCode::Version =>
263 {
264 let version = misc::get_version().to_string();
265 let server_version = read.text.unwrap();
266
267 if server_version != version
269 {
270 tx.send(ClientEvent::IncompatibleVersion(version.clone(), server_version)).unwrap();
271 }
272
273 network::send(&mut streams.1.lock().unwrap(), MessagePacket
275 {
276 text: Some(version),
277 code: Some(MessageCode::Version),
278 ..Default::default()
279 }, Some(&keys));
280
281 continue;
282 }
283
284 MessageCode::Welcome =>
286 {
287 let welcome_json: Value = serde_json::from_str(&read.text.unwrap()).expect("Parsing welcome json failed"); min_pass = Some(welcome_json["min_pass"].as_u64().expect("Invalid welcome json"));
292 max_uname = Some(welcome_json["max_uname"].as_u64().expect("Invalid welcome json"));
293 min_uname = Some(welcome_json["min_uname"].as_u64().expect("Invalid welcome json"));
294 options::set_server_username(welcome_json["server_uname"].as_str().expect("Invalid welcome json"));
295
296 tx.send(ClientEvent::Connected(welcome_json["server_name"].as_str().expect("Invalid welcome json").to_string())).unwrap();
297 },
298
299 MessageCode::Rekey =>
301 {
302 key_exchange(streams, &mut keys, &tx);
304 }
305
306 MessageCode::Username =>
308 {
309 tx.send(ClientEvent::Clear(2)).unwrap();
310
311 if invalid_username
313 {
314 tx.send(ClientEvent::UsernameRejected).unwrap();
315 } else {
317 invalid_username = true;
319 }
320
321 tx.send(ClientEvent::Username(disabled_registration, min_uname.unwrap(), max_uname.unwrap())).unwrap();
322 },
323
324 MessageCode::PasswordR =>
326 {
327 tx.send(ClientEvent::Clear(3)).unwrap();
328 options::set_asking_password(true);
329
330 if invalid_password
332 {
333 tx.send(ClientEvent::PasswordRejected(min_pass.unwrap())).unwrap();
334 } else
335 {
336 invalid_password = true;
337 }
338
339 tx.send(ClientEvent::Register).unwrap();
340 },
341
342 MessageCode::PasswordL =>
344 {
345 options::set_asking_password(true);
346 tx.send(ClientEvent::Login).unwrap();
347 },
348
349 MessageCode::Accept =>
351 {
352 tx.send(ClientEvent::Authenticated).unwrap();
353
354 id = read.text.unwrap_or("0".to_string()).parse().unwrap();
356
357 options::set_sending_messages(true);
359 },
360
361 MessageCode::Join =>
363 {
364 tx.send(ClientEvent::Clear(2)).unwrap();
365
366 let user = read.text.unwrap();
367
368 if first_message
369 {
370 tx.send(ClientEvent::ExtraSpace).unwrap();
371 username = Some(user.clone());
372 first_message = false;
373 }
374
375 tx.send(ClientEvent::Join(user)).unwrap();
376 }
377
378 MessageCode::Leave =>
380 {
381 tx.send(ClientEvent::Leave(read.text.unwrap())).unwrap();
382 voice_client::remove_consumer(&read.id.unwrap());
383 },
384
385 MessageCode::Channel =>
387 {
388 voice_client::remove_all_consumers();
390
391 channel = if let Some(c) = read.text
392 {
393 format!("#{c} | ")
394 } else
395 {
396 String::new()
397 };
398
399 tx.send(ClientEvent::Clear(1)).unwrap();
400 },
401
402 MessageCode::Voice =>
404 {
405 if options::socks5_enabled()
406 {
407 tx.send(ClientEvent::Socks5Voice).unwrap();
408 continue;
409 }
410
411 tx.send(if voice_options::swap_use_voice()
413 {
414 let username = username.clone();
415 let voice_tx = tx.clone();
416 let stream = streams.1.clone();
417 thread::spawn(move || voice_client::listen_server_voice(id, username.unwrap(), voice_tx, stream));
418 ClientEvent::VoiceEnabled
419 } else
420 {
421 ClientEvent::VoiceDisabled
422 }).unwrap();
423 },
424
425 MessageCode::VoiceClients =>
427 {
428 let clients: Vec<(usize, String)> = serde_json::from_str(&read.text.unwrap()).expect("Parsing welcome json failed");
430
431 for (id, username) in clients
433 {
434 voice_client::add_consumer(id, username);
435 }
436 }
437
438 MessageCode::ChannelJoin =>
440 {
441 let joined_id = read.id.unwrap();
442 if voice_options::get_use_voice() && id != joined_id
443 {
444 voice_client::add_consumer(read.id.unwrap(), read.username.unwrap());
445 }
446 },
447
448 MessageCode::ChannelLeave =>
450 {
451 voice_client::remove_consumer(&read.id.unwrap());
452 },
453
454 MessageCode::List =>
456 {
457 if !options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
458 tx.send(ClientEvent::List(serde_json::from_str(&read.text.unwrap()).unwrap())).unwrap();
459 extra_space = true;
460 options::set_extra_space(true);
461 },
462
463 MessageCode::Upload =>
465 {
466 let payload = read.file.unwrap();
468 let file_hash = payload.hash.unwrap();
469
470 let path = ACTIVE_UPLOADS.lock().unwrap().remove(&file_hash).unwrap(); let filename = path.clone().file_name().and_then(|n| n.to_str()
473 .map(|s| s.to_string())).unwrap_or(String::from("Unknown")); let upload_stream = streams.1.clone();
477
478 thread::spawn(move || network::send_file(path, upload_stream,
480 payload.uid, MessageCode::Upload, options::get_keys().as_ref()));
481
482 tx.send(ClientEvent::Upload(filename)).unwrap();
483 },
484
485 MessageCode::Download =>
487 {
488 let file = read.file.unwrap();
489 let uid = file.uid;
490
491 if let Some(mut active) = network::ACTIVE_FILESHARES.get_mut(&uid)
493 {
494 let chunk_data = file.data.unwrap();
495
496 if active.file.write_all(&chunk_data).is_ok()
498 {
499 active.current_size += chunk_data.len() as u64;
501
502 active.hasher.update(&chunk_data);
504
505 if active.current_size == active.size
507 {
508 let filename = active.filename.clone();
509 let final_hash: [u8; 32] = active.hasher.clone().finalize().into();
510
511 tx.send(if active.hash == final_hash
513 {
514 ClientEvent::Downloaded(filename)
515 } else
516 {
517 ClientEvent::DownloadFailed(filename)
518 }).unwrap();
519
520 drop(active);
522 network::ACTIVE_FILESHARES.remove(&uid);
523 }
524 }
525 } else
526 {
527 let download_dir = config::read_config::<String>("download_directory")
529 .replace("{HOME}", dirs::home_dir().expect("Could not determine home directory")
530 .to_str().expect("Invalid home directory"));
531
532 let filename = Path::new(&file.filename.unwrap())
534 .file_name()
535 .and_then(|f| f.to_str())
536 .unwrap_or("unnamed_file")
537 .to_string();
538
539 fs::create_dir_all(&download_dir).expect("Creating download directory failed");
541
542 network::ACTIVE_FILESHARES.insert(uid, ActiveFileshare
543 {
544 file: File::create(Path::new(&download_dir)
545 .join(&filename)).expect("Creating download file failed"),
546 size: file.size.unwrap(),
547 current_size: 0,
548 hash: file.hash.unwrap(),
549 hasher: Sha256::new(),
550 filename: filename.clone(),
551 });
552
553 tx.send(ClientEvent::Download(filename)).unwrap();
555 }
556 },
557
558 MessageCode::Uploaded =>
560 {
561 tx.send(ClientEvent::Uploaded(read.username.unwrap(), read.text.unwrap())).unwrap();
562 },
563
564 MessageCode::Files =>
566 {
567 let uploads_json: Vec<Value> = serde_json::from_str(&read.text.unwrap()).unwrap();
569
570 if !uploads_json.is_empty()
571 {
572 if !options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
573 extra_space = true;
574 options::set_extra_space(true);
575 }
576
577 tx.send(ClientEvent::Files(uploads_json)).unwrap();
578 },
579
580 MessageCode::PrivateMessage =>
582 {
583 tx.send(ClientEvent::PrivateMessageRecv(read.username.unwrap(), read.id.unwrap(), read.text.unwrap())).unwrap();
584 },
585
586 MessageCode::PrivateMessageBack =>
588 {
589 tx.send(ClientEvent::PrivateMessageSent(read.username.unwrap(), read.id.unwrap(), read.text.unwrap())).unwrap();
590 },
591
592 MessageCode::SpamWarning =>
594 {
595 tx.send(ClientEvent::SpamWarning).unwrap();
596 },
597
598 MessageCode::RegisterDisabled =>
600 {
601 disabled_registration = true;
602 },
603
604 MessageCode::InvalidUsage =>
606 {
607 tx.send(ClientEvent::InvalidUsage).unwrap();
608 },
609
610 MessageCode::InvalidFeature =>
612 {
613 tx.send(ClientEvent::DisabledFeature).unwrap();
614 },
615
616 MessageCode::Disconnect =>
618 {
619 tx.send(ClientEvent::Quit).unwrap();
620 return;
621 },
622
623 _ => continue }
625 } else {
627 tx.send(ClientEvent::Message(read)).unwrap();
628 }
629
630 tx.send(ClientEvent::Prompt(channel.clone(), options::INPUT_READ.lock().unwrap().iter().collect::<String>())).unwrap();
632 if !extra_space { options::set_extra_space(false); } }
634}