1pub mod file;
21
22use std::
23{
24 thread,
25 net::TcpStream,
26 io::{ Error, Write },
27 collections::HashMap,
28 path::PathBuf,
29 sync::
30 {
31 Arc,
32 Mutex,
33 LazyLock,
34 mpsc::Sender,
35 },
36};
37
38use rand::
39{
40 TryRng,
41 rngs::SysRng,
42};
43
44use socks::Socks5Stream;
45
46use zeroize::Zeroizing;
47
48use serde_json::Value;
49
50use semver::Version;
51
52use crate::
53{
54 options,
55 misc,
56 crypto::kex,
57 consts::{ self, Streams },
58 config::{ self, TofuCode },
59 network::
60 {
61 self,
62 MessageCode,
63 MessagePacket,
64 voice::
65 {
66 client as voice_client,
67 options as voice_options,
68 }
69 },
70};
71
72pub struct VoiceUser
74{
75 pub id: usize, pub username: String, pub is_speaking: bool, pub latency: u128, pub is_local: bool, }
81
82pub enum ClientEvent
84{
85 Register, Login, Authenticated, Connected(String), Message(MessagePacket), Prompt(String), PrivateMessageSent(String, usize, String), PrivateMessageRecv(String, usize, String), TofuError(TofuCode), VoiceActivity(Vec<VoiceUser>), Join(String), Leave(String), Clear(usize), InvalidUsage, VersionFailed, VersionMismatch(String, String), 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>), UploadLimit, ExtraSpace, IncompatibleVersion(String, String), UsernameRejected, PasswordRejected(u64), SpamWarning, Socks5Voice, DisabledFeature, Quit, }
122
123pub static ACTIVE_UPLOADS: LazyLock<Arc<Mutex<HashMap<[u8; 32], PathBuf>>>> = LazyLock::new(|| {
126 Arc::new(Mutex::new(HashMap::new()))
127});
128
129fn key_exchange
132(
133 streams: &mut Streams,
134 keys: &mut consts::SharedKeys,
135 tx: &Sender<ClientEvent>,
136 exchange_keys: Option<&consts::SharedKeys>,
137) -> bool {
139 let message = loop
141 {
142 let received = network::receive(streams, exchange_keys, None).unwrap();
144
145 if received.code == Some(MessageCode::KeyExchange) { break received; }
146 };
147
148 let message_text = message.text.as_ref().unwrap();
149
150 let server_keys: Value = serde_json::from_str(message_text).expect("Failed to parse server keys JSON");
152 let server_ecc_pk = server_keys["ecc"].as_str().expect("Parsing server ECC key failed");
153 let server_pq_pk = server_keys["pq"].as_str().expect("Parsing server PQ key failed");
154
155 match config::server_keys_check(&streams.0.peer_addr().unwrap().ip().to_string(), message_text)
157 {
158 TofuCode::Valid => {},
159
160 status @ (TofuCode::Mismatch | TofuCode::Unknown(_, _)) =>
161 {
162 network::send(&mut streams.1.lock().unwrap(), MessagePacket
164 {
165 code: Some(MessageCode::Disconnect),
166 ..Default::default()
167 }, None);
168
169 tx.send(ClientEvent::TofuError(status)).unwrap();
171
172 return false;
174 },
175 }
176
177 let (sk, pk) = kex::generate_ephemeral_keys();
179
180 let (pq_ciphertext, pq_secret) = kex::encapsulate_pq(server_pq_pk);
182
183 let response_text = serde_json::json!
185 ({
186 "ecc": pk,
187 "pq": pq_ciphertext,
188 }).to_string();
189
190 network::send(&mut streams.1.lock().unwrap(), MessagePacket
192 {
193 text: Some(response_text),
194 code: Some(MessageCode::KeyExchange),
195 ..Default::default()
196 }, exchange_keys);
197
198 *keys = kex::derive_shared_secret(sk, server_ecc_pk.to_string(), pq_secret).expect("Shared secret derivation failed");
200
201 options::set_keys(keys.clone());
203
204 true
205}
206
207pub fn connect(connecting_addr: String) -> Result<TcpStream, Error> {
210 if !options::socks5_enabled() {
212 TcpStream::connect(connecting_addr)
213 } else {
215 Socks5Stream::connect(config::read_config::<String>("socks5_addr"), connecting_addr.as_str())
216 .map(|s| s.into_inner())
217 }.and_then(|s|
218 {
219 s.set_nodelay(true)?;
221 Ok(s)
222 })
223}
224
225pub fn listen_server(streams: &mut Streams, tx: Sender<ClientEvent>) {
227 let mut header = [0u8; 32];
229 SysRng.try_fill_bytes(&mut header).unwrap(); options::set_obfuscation_key(&header);
231 streams.1.lock().unwrap().write_all(&header).unwrap();
232
233 let mut keys = (Zeroizing::new(vec![]), Zeroizing::new(vec![]));
235 if !key_exchange(streams, &mut keys, &tx, None) { return; }
236
237 let mut min_pass: Option<u64> = None;
239 let mut max_uname: Option<u64> = None;
240 let mut min_uname: Option<u64> = None;
241
242 let mut invalid_username = false; let mut invalid_password = false;
244
245 let mut disabled_registration = false; let mut first_message = true;
249 let mut extra_space: bool;
250
251 let mut id = 0usize; let mut username: Option<String> = None;
254
255 loop
257 {
258 let read = match network::receive(streams, Some(&keys), None)
259 {
260 Some(packet) => packet,
261 None => MessagePacket
262 {
263 code: Some(MessageCode::Disconnect),
264 ..Default::default()
265 }
266 };
267
268 if read.id.is_some() && options::is_muted(read.id) { continue; }
270
271 if read.code == Some(MessageCode::KeepAlive)
273 {
274 network::send(&mut streams.1.lock().unwrap(), MessagePacket
276 {
277 code: Some(MessageCode::KeepAlive),
278 ..Default::default()
279 }, options::get_keys().as_ref());
280 continue;
281 }
282
283 extra_space = false; if options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
287
288 if let Some(code) = read.code
290 {
291 match code
292 {
293 MessageCode::Version =>
295 {
296 let version = misc::get_version().to_string();
297 let server_version = read.text.unwrap();
298
299 if server_version != version
301 {
302 tx.send(ClientEvent::IncompatibleVersion(version.clone(), server_version)).unwrap();
303 }
304
305 network::send(&mut streams.1.lock().unwrap(), MessagePacket
307 {
308 text: Some(version),
309 code: Some(MessageCode::Version),
310 ..Default::default()
311 }, Some(&keys));
312
313 continue;
314 }
315
316 MessageCode::Welcome =>
318 {
319 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"));
324 max_uname = Some(welcome_json["max_uname"].as_u64().expect("Invalid welcome json"));
325 min_uname = Some(welcome_json["min_uname"].as_u64().expect("Invalid welcome json"));
326 options::set_server_username(welcome_json["server_uname"].as_str().expect("Invalid welcome json"));
327
328 let client_hash = env!("WHY2_GIT_HASH");
330 let server_hash = welcome_json["git_hash"].as_str().expect("Invalid welcome json");
331 if !client_hash.is_empty() && !server_hash.is_empty() && client_hash != server_hash
332 {
333 tx.send(ClientEvent::VersionMismatch(client_hash.to_string(), server_hash.to_string())).unwrap();
335 }
336
337 tx.send(ClientEvent::Connected(welcome_json["server_name"].as_str().expect("Invalid welcome json").to_string())).unwrap();
338 },
339
340 MessageCode::Rekey =>
342 {
343 let current_keys = keys.clone();
345 key_exchange(streams, &mut keys, &tx, Some(¤t_keys));
346 }
347
348 MessageCode::Username =>
350 {
351 tx.send(ClientEvent::Clear(2)).unwrap();
352
353 if invalid_username
355 {
356 tx.send(ClientEvent::UsernameRejected).unwrap();
357 } else {
359 invalid_username = true;
361 }
362
363 tx.send(ClientEvent::Username(disabled_registration, min_uname.unwrap(), max_uname.unwrap())).unwrap();
364 },
365
366 MessageCode::PasswordR =>
368 {
369 tx.send(ClientEvent::Clear(3)).unwrap();
370 options::set_asking_password(true);
371
372 if invalid_password
374 {
375 tx.send(ClientEvent::PasswordRejected(min_pass.unwrap())).unwrap();
376 } else
377 {
378 invalid_password = true;
379 }
380
381 tx.send(ClientEvent::Register).unwrap();
382 },
383
384 MessageCode::PasswordL =>
386 {
387 options::set_asking_password(true);
388 tx.send(ClientEvent::Login).unwrap();
389 },
390
391 MessageCode::Accept =>
393 {
394 tx.send(ClientEvent::Authenticated).unwrap();
395
396 id = read.text.unwrap_or_else(|| "0".to_string()).parse().unwrap();
398
399 options::set_sending_messages(true);
401 },
402
403 MessageCode::Join =>
405 {
406 tx.send(ClientEvent::Clear(2)).unwrap();
407
408 let user = read.text.unwrap();
409
410 if first_message
411 {
412 tx.send(ClientEvent::ExtraSpace).unwrap();
413 username = Some(user.clone());
414 first_message = false;
415 }
416
417 tx.send(ClientEvent::Join(user)).unwrap();
418 }
419
420 MessageCode::Leave =>
422 {
423 tx.send(ClientEvent::Leave(read.text.unwrap())).unwrap();
424 voice_client::remove_consumer(&read.id.unwrap());
425 },
426
427 MessageCode::Channel =>
429 {
430 voice_client::remove_all_consumers();
432
433 options::set_channel(read.text.unwrap_or_else(|| String::new()));
434
435 tx.send(ClientEvent::Clear(1)).unwrap();
436 },
437
438 MessageCode::Voice =>
440 {
441 if options::socks5_enabled()
442 {
443 tx.send(ClientEvent::Socks5Voice).unwrap();
444 continue;
445 }
446
447 tx.send(if voice_options::swap_use_voice()
449 {
450 let username = username.clone();
451 let voice_tx = tx.clone();
452 let stream = streams.1.clone();
453 thread::spawn(move || voice_client::listen_server_voice(id, username.unwrap(), voice_tx, stream));
454 ClientEvent::VoiceEnabled
455 } else
456 {
457 ClientEvent::VoiceDisabled
458 }).unwrap();
459 },
460
461 MessageCode::VoiceClients =>
463 {
464 let clients: Vec<(usize, String)> = serde_json::from_str(&read.text.unwrap()).expect("Parsing welcome json failed");
466
467 for (id, username) in clients
469 {
470 voice_client::add_consumer(id, username);
471 }
472 }
473
474 MessageCode::ChannelJoin =>
476 {
477 let joined_id = read.id.unwrap();
478 if voice_options::get_use_voice() && id != joined_id
479 {
480 voice_client::add_consumer(read.id.unwrap(), read.username.unwrap());
481 }
482 },
483
484 MessageCode::ChannelLeave =>
486 {
487 voice_client::remove_consumer(&read.id.unwrap());
488 },
489
490 MessageCode::List =>
492 {
493 if !options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
494 tx.send(ClientEvent::List(serde_json::from_str(&read.text.unwrap()).unwrap())).unwrap();
495 extra_space = true;
496 options::set_extra_space(true);
497 },
498
499 MessageCode::Upload =>
501 {
502 let file_tx = tx.clone(); thread::spawn(move || file::upload(read.file.unwrap(), file_tx));
505 continue;
506 },
507
508 MessageCode::Download =>
510 {
511 let file_tx = tx.clone(); thread::spawn(move || file::download(read.file.unwrap(), file_tx));
514 continue;
515 },
516
517 MessageCode::Uploaded =>
519 {
520 tx.send(ClientEvent::Uploaded(read.username.unwrap(), read.text.unwrap())).unwrap();
521 },
522
523 MessageCode::Files =>
525 {
526 let uploads_json: Vec<Value> = serde_json::from_str(&read.text.unwrap()).unwrap();
528
529 if !uploads_json.is_empty()
530 {
531 if !options::get_extra_space() { tx.send(ClientEvent::ExtraSpace).unwrap(); }
532 extra_space = true;
533 options::set_extra_space(true);
534 }
535
536 tx.send(ClientEvent::Files(uploads_json)).unwrap();
537 },
538
539 MessageCode::UploadLimit =>
541 {
542 tx.send(ClientEvent::UploadLimit).unwrap();
543 },
544
545 MessageCode::PrivateMessage =>
547 {
548 tx.send(ClientEvent::PrivateMessageRecv(read.username.unwrap(), read.id.unwrap(), read.text.unwrap())).unwrap();
549 },
550
551 MessageCode::PrivateMessageBack =>
553 {
554 tx.send(ClientEvent::PrivateMessageSent(read.username.unwrap(), read.id.unwrap(), read.text.unwrap())).unwrap();
555 },
556
557 MessageCode::SpamWarning =>
559 {
560 tx.send(ClientEvent::SpamWarning).unwrap();
561 },
562
563 MessageCode::RegisterDisabled =>
565 {
566 disabled_registration = true;
567 },
568
569 MessageCode::InvalidUsage =>
571 {
572 tx.send(ClientEvent::InvalidUsage).unwrap();
573 },
574
575 MessageCode::InvalidFeature =>
577 {
578 tx.send(ClientEvent::DisabledFeature).unwrap();
579 },
580
581 MessageCode::Disconnect =>
583 {
584 tx.send(ClientEvent::Quit).unwrap();
585 return;
586 },
587
588 _ => continue }
590 } else {
592 tx.send(ClientEvent::Message(read)).unwrap();
593 }
594
595 tx.send(ClientEvent::Prompt(options::INPUT_READ.lock().unwrap().iter().collect::<String>())).unwrap();
597 if !extra_space { options::set_extra_space(false); } }
599}