42
42
#ifdef HAVE_VOICE
43
43
#include < sodium.h>
44
44
#include < opus/opus.h>
45
+ #include " dave/session.h"
45
46
#else
46
47
struct OpusDecoder {};
47
48
struct OpusEncoder {};
48
49
struct OpusRepacketizer {};
50
+ struct dpp ::dave::Session {};
49
51
#endif
50
52
51
53
namespace dpp {
@@ -70,6 +72,10 @@ constexpr uint8_t voice_protocol_version = 8;
70
72
*/
71
73
static std::string external_ip;
72
74
75
+ struct dave_transient_key {
76
+ std::shared_ptr<::mlspp::SignaturePrivateKey> mls_key;
77
+ };
78
+
73
79
/* *
74
80
* @brief Transport encryption type (libsodium)
75
81
*/
@@ -483,40 +489,49 @@ int discord_voice_client::udp_recv(char* data, size_t max_length)
483
489
return (int ) recv (this ->fd , data, (int )max_length, 0 );
484
490
}
485
491
492
+ std::vector<uint8_t > dave_binary_header_t::get_data (size_t length) const {
493
+ return std::vector<uint8_t >(package, package + length - sizeof (dave_binary_header_t ));
494
+ }
495
+
486
496
bool discord_voice_client::handle_frame (const std::string &data, ws_opcode opcode)
487
497
{
488
498
json j;
489
499
490
500
/* *
491
501
* MLS frames come in as type OP_BINARY, we can also reply to them as type OP_BINARY.
492
502
*/
493
- if (opcode == OP_BINARY && data.size () >= sizeof (dave_binary_header_t )) {
494
-
495
- log (dpp::ll_trace, " R: " + dpp::utility::debug_dump ((uint8_t *)(data.data ()), data.length ()));
503
+ if (opcode == OP_BINARY && data.size () >= sizeof (dave_binary_header_t ) && dave_session && transient_key && transient_key->mls_key ) {
496
504
497
- dave_binary_header_t dave_header{};
498
- std::memcpy (&dave_header, data.data (), sizeof (dave_binary_header_t ));
505
+ auto * dave_header = reinterpret_cast <const dave_binary_header_t *>(data.data ());
499
506
500
- switch (dave_header. opcode ) {
507
+ switch (dave_header-> opcode ) {
501
508
case voice_client_dave_mls_external_sender: {
502
509
log (ll_debug, " voice_client_dave_mls_external_sender" );
510
+ dave_session->SetExternalSender (dave_header->get_data (data.length ()));
503
511
}
504
- break ;
512
+ break ;
505
513
case voice_client_dave_mls_proposals: {
506
514
log (ll_debug, " voice_client_dave_mls_proposals" );
515
+ std::optional<std::vector<uint8_t >> response = dave_session->ProcessProposals (dave_header->get_data (data.length ()), dave_mls_user_list);
516
+ if (response.has_value ()) {
517
+ auto r = response.value ();
518
+ r.insert (r.begin (), voice_client_dave_mls_commit_message);
519
+ this ->write (std::string_view (reinterpret_cast <const char *>(r.data ()), r.size ()), OP_BINARY);
520
+ }
507
521
}
508
- break ;
522
+ break ;
509
523
case voice_client_dave_announce_commit_transaction: {
510
524
log (ll_debug, " voice_client_dave_announce_commit_transaction" );
511
525
}
512
- break ;
526
+ break ;
513
527
case voice_client_dave_mls_welcome: {
514
528
log (ll_debug, " voice_client_dave_mls_welcome" );
515
529
}
516
- break ;
530
+ break ;
517
531
default :
518
532
log (ll_debug, " Unexpected DAVE frame opcode" );
519
- break ;
533
+ log (dpp::ll_trace, " R: " + dpp::utility::debug_dump ((uint8_t *)(data.data ()), data.length ()));
534
+ break ;
520
535
}
521
536
522
537
return true ;
@@ -563,8 +578,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod
563
578
}
564
579
break ;
565
580
case voice_opcode_multiple_clients_connect: {
566
- auto client_list = j[" d" ][" user_ids" ];
567
- log (ll_debug, " Number of new clients in voice channel: " + std::to_string (client_list .size ()));
581
+ dave_mls_user_list = j[" d" ][" user_ids" ];
582
+ log (ll_debug, " Number of clients in voice channel: " + std::to_string (dave_mls_user_list .size ()));
568
583
}
569
584
break ;
570
585
/* Client Disconnect */
@@ -673,6 +688,13 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod
673
688
log (ll_error, " We requested DAVE E2EE but didn't receive it from the server, downgrading..." );
674
689
dave_version = dave_version_none;
675
690
send_silence (20 );
691
+ } else {
692
+ dave_session = std::make_unique<dave::mls::Session>(
693
+ nullptr , sessionid, [this ](std::string const & s1, std::string const & s2) {
694
+ log (ll_debug, " Dave session constructor callback: " + s1 + " , " + s2);
695
+ });
696
+ transient_key = std::make_unique<dave_transient_key>();
697
+ dave_session->Init (dave::MaxSupportedProtocolVersion (), channel_id, creator->me .id .str (), transient_key->mls_key );
676
698
}
677
699
} else {
678
700
/* This is needed to start voice receiving and make sure that the start of sending isn't cut off */
@@ -1433,17 +1455,18 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet
1433
1455
memcpy (encrypt_nonce, &noncel, sizeof (noncel));
1434
1456
1435
1457
/* Execute */
1436
- int r = crypto_aead_xchacha20poly1305_ietf_encrypt (
1437
- payload.data () + sizeof (header),
1438
- nullptr ,
1439
- encoded_audio.data (),
1440
- encoded_audio_length,
1441
- /* The RTP Header as Additional Data */
1442
- reinterpret_cast <const unsigned char *>(&header),
1443
- sizeof (header),
1444
- nullptr ,
1445
- static_cast <const unsigned char *>(encrypt_nonce),
1446
- secret_key.data ());
1458
+ crypto_aead_xchacha20poly1305_ietf_encrypt (
1459
+ payload.data () + sizeof (header),
1460
+ nullptr ,
1461
+ encoded_audio.data (),
1462
+ encoded_audio_length,
1463
+ /* The RTP Header as Additional Data */
1464
+ reinterpret_cast <const unsigned char *>(&header),
1465
+ sizeof (header),
1466
+ nullptr ,
1467
+ static_cast <const unsigned char *>(encrypt_nonce),
1468
+ secret_key.data ()
1469
+ );
1447
1470
1448
1471
/* Append the 4 byte nonce to the resulting payload */
1449
1472
std::memcpy (payload.data () + payload.size () - sizeof (noncel), &noncel, sizeof (noncel));
0 commit comments