Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discord DAVE Protocol (E2EE) for voice #1258

Merged
merged 123 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
037790d
[bot] VCPKG info update [skip ci]
braindigitalis Sep 21, 2024
775b474
Merge branch 'dev' of github.com:brainboxdotcc/DPP
braindigitalis Sep 22, 2024
f892394
Merge branch 'dev' of github.com:brainboxdotcc/DPP
braindigitalis Sep 23, 2024
3ec2a6f
feat: DAVE E2EE
braindigitalis Sep 24, 2024
d8886d2
fix conflict
braindigitalis Sep 24, 2024
de5ce18
test: dave test program
braindigitalis Sep 24, 2024
27ae746
binary frame parse
braindigitalis Sep 25, 2024
8ec080b
refactor: websocket; allow passing the frame type up the stack
braindigitalis Sep 25, 2024
cb418e3
debugging, correctly set session id
braindigitalis Sep 25, 2024
5e9a91f
add seq_ack to resume
braindigitalis Sep 25, 2024
af3d113
refactor: cleanups
braindigitalis Sep 25, 2024
dc77f0f
refactor: change raw pointer for secret key array to std::array
braindigitalis Sep 25, 2024
12f6bef
docs: change comment about sodium secret_key array
braindigitalis Sep 25, 2024
39eeece
media_session_id is not required
braindigitalis Sep 25, 2024
97eebb4
DAVE
braindigitalis Sep 25, 2024
e33f95e
make hpke use dpp nlohmann
braindigitalis Sep 25, 2024
32589a0
DAVE
braindigitalis Sep 25, 2024
7459096
make warns non-fatal in third party deps, isnt our job to fix
braindigitalis Sep 25, 2024
1fbf2aa
openssl junk
braindigitalis Sep 25, 2024
4ba4eec
work around defect with stringstream inplace
braindigitalis Sep 25, 2024
f897e11
fix: include weirdness
braindigitalis Sep 25, 2024
5a51a63
fix: again attempt to fix the .str and stringstream weirdness, thanks…
braindigitalis Sep 25, 2024
e40c638
add FindFilesystem for gcc <= 9
braindigitalis Sep 25, 2024
e268000
set openssl version (for mlspp to inherit) on windows, hard code to 1…
braindigitalis Sep 25, 2024
7682c78
remove libcrypto link from hpke, it is linked by parent project
braindigitalis Sep 25, 2024
9e5ed67
build: remove installation of dependent .a files
braindigitalis Sep 25, 2024
fe7f915
disable warnings-as-errors in mlspp
braindigitalis Sep 25, 2024
41d420c
fix 32 bit windows compilation of mlspp
braindigitalis Sep 25, 2024
d2a3cf0
make filesystem not required (required breaks 32 bit windows)
braindigitalis Sep 26, 2024
d26a7be
fix for working around windows 32 bit madness
braindigitalis Sep 26, 2024
47bdf18
feat: receive_sequence for v8 voice gateway
Neko-Life Sep 26, 2024
185d4bf
feat: receive_sequence for v8 voice gateway (#1249)
braindigitalis Sep 26, 2024
1b254db
Merge branch 'dev' of github.com:brainboxdotcc/DPP into dave
braindigitalis Sep 26, 2024
bebe921
refactor: BoringSSLEncryptor -> OpenSSLEncryptor
braindigitalis Sep 26, 2024
0d6aff8
begin refactoring to our namespace and code style
braindigitalis Sep 26, 2024
7e1d377
remove mpack.variant, it is only used for C++11 and C++14, and macos …
braindigitalis Sep 27, 2024
4dab53c
negotiation in binary
braindigitalis Sep 28, 2024
9853031
doesnt work yet
braindigitalis Sep 28, 2024
2e8000e
refactor AEAD openssl cipher
braindigitalis Sep 28, 2024
ca0a82d
fix: DAVE protocol initiation for BOB
braindigitalis Oct 1, 2024
6188fc5
DAVE: ratcheting works if second to join, not if first
braindigitalis Oct 1, 2024
49d4d0f
now joins MLS group in both flows
braindigitalis Oct 2, 2024
c25e032
Merge branch 'dev' of github.com:brainboxdotcc/DPP into dave
braindigitalis Oct 2, 2024
c5e7664
Merge branch 'master' of github.com:brainboxdotcc/DPP into dave
braindigitalis Oct 2, 2024
cd68bbf
voice client methods for DAVE stuff
braindigitalis Oct 2, 2024
8e99caa
remove test calls
braindigitalis Oct 2, 2024
89e412e
remove deleted ctors which break older clang and g++
braindigitalis Oct 3, 2024
5afa97c
move dave session into mls state
braindigitalis Oct 3, 2024
ef85471
g++8 fixes
braindigitalis Oct 3, 2024
d962ad2
start trimming out stuff where HAVE_VOICE not set
braindigitalis Oct 3, 2024
020074a
dont build dave and mlspp if HAVE_VOICE is not set
braindigitalis Oct 3, 2024
ff44013
add copyright headers, with attribution for libdave and leb128 where …
braindigitalis Oct 3, 2024
a5f926f
start splitting out discordvoiceclient into smaller files with less heft
braindigitalis Oct 3, 2024
aafe8ee
splitting out of voice parts into smaller files
braindigitalis Oct 3, 2024
dbb3d95
define static
braindigitalis Oct 3, 2024
4484cd1
define static
braindigitalis Oct 3, 2024
4e0b8dd
fix missing includes
braindigitalis Oct 3, 2024
4d5507a
fix missing includes
braindigitalis Oct 3, 2024
183e1b8
fix includes
braindigitalis Oct 3, 2024
f5a1396
fix missing struct
braindigitalis Oct 3, 2024
5c34c87
split off more stuff
braindigitalis Oct 3, 2024
294397b
move isa_detection
braindigitalis Oct 3, 2024
ed01cf5
split out ip discoverey and improve it from a bunch of punning
braindigitalis Oct 3, 2024
7127131
improve ip detection
braindigitalis Oct 4, 2024
27c1b07
fix error with C++20 assumption
braindigitalis Oct 4, 2024
5838f50
non-UB type punning function
braindigitalis Oct 4, 2024
8dcb87e
fix: vs doesnt like that template type
braindigitalis Oct 4, 2024
1df9584
get rid, cant make this work in vs
braindigitalis Oct 4, 2024
d92d46b
refactor: two casts are not required, the called C functions accept v…
braindigitalis Oct 4, 2024
0ad6a45
discord unit tests
braindigitalis Oct 4, 2024
c8b8b0b
fix: this should now be in right position, but does not work
braindigitalis Oct 4, 2024
03e7656
IT WORKS
braindigitalis Oct 4, 2024
c979ba2
remove discord encryptor tests
braindigitalis Oct 4, 2024
17595d1
for windows :(
braindigitalis Oct 4, 2024
b73d0d1
Merge branch 'dev' of github.com:brainboxdotcc/DPP into dave
braindigitalis Oct 4, 2024
c4899a2
not sure where these docs changes came from
braindigitalis Oct 4, 2024
80a3eeb
fix the word now that somehow got lowercased everywhere. they shouldn…
braindigitalis Oct 4, 2024
4c50366
Now
braindigitalis Oct 4, 2024
e7ad7ca
add DAVE to voice model
braindigitalis Oct 4, 2024
33f420d
improved voice model text
braindigitalis Oct 4, 2024
7a17450
feat: DAVE received audio decryption
braindigitalis Oct 5, 2024
afd906c
feat: DAVE received audio decryption
braindigitalis Oct 5, 2024
c2722e5
fix: remove debug output
braindigitalis Oct 5, 2024
46e048f
start refactoring naming scheme
braindigitalis Oct 5, 2024
1dc8e50
refactor libdave naming
braindigitalis Oct 5, 2024
e057e2a
rename horrible k constants
braindigitalis Oct 5, 2024
9c53286
refactor naming
braindigitalis Oct 5, 2024
4fa6ccb
refactor: libdave -> tab indent
braindigitalis Oct 5, 2024
c2f608b
refactor: naming
braindigitalis Oct 5, 2024
361ef8b
fix failed refactors
braindigitalis Oct 5, 2024
202c2b5
Session -> session
braindigitalis Oct 5, 2024
1cb9675
rename session methods
braindigitalis Oct 5, 2024
c32e1ff
refactor: code style
braindigitalis Oct 5, 2024
0dba783
fix: make ready event work with cancelled dave protocol
Neko-Life Oct 5, 2024
e7cb773
rename constants and enums
braindigitalis Oct 5, 2024
7aeda79
feat: working downgrade/upgrade on user join/leave vc
Neko-Life Oct 6, 2024
856ee3b
Feat/dave downgrade-upgrade (#1260)
braindigitalis Oct 6, 2024
caddf0a
remove C asserts
braindigitalis Oct 6, 2024
d60f706
document array_view
braindigitalis Oct 6, 2024
8a71378
document cipher_interface
braindigitalis Oct 6, 2024
dfc9275
docs: docblock comments
braindigitalis Oct 6, 2024
1a02080
document decryptor, encryptor, frame processor
braindigitalis Oct 6, 2024
ad12b29
document frame processor
braindigitalis Oct 6, 2024
d4aba45
docs: document classes for DAVE
braindigitalis Oct 6, 2024
433ebc5
docs: document persisted key pair
braindigitalis Oct 6, 2024
260a389
docs: document remaining classes and types
braindigitalis Oct 6, 2024
cef07fb
audio frame image
braindigitalis Oct 6, 2024
936ac59
add dave to guild_member_connect
braindigitalis Oct 6, 2024
5f6960f
code review
braindigitalis Oct 6, 2024
07c2d9c
NEW
braindigitalis Oct 6, 2024
9b39d15
@brief
braindigitalis Oct 6, 2024
4a7829d
missing }, and remove unneeded warn disable
braindigitalis Oct 6, 2024
c8774d4
refactor: nuke a whole load of C style casts from orbit
braindigitalis Oct 6, 2024
54ab910
refactor: remove some of the logging in libdave replacing it with dpp…
braindigitalis Oct 6, 2024
11e59ca
fixes missing documentation blocks
braindigitalis Oct 7, 2024
953ae76
IP discovery without UB
braindigitalis Oct 7, 2024
ca15314
Catch ... instead of exception ref
braindigitalis Oct 7, 2024
305ca59
refactor: non-UB dave_binary_header_t
braindigitalis Oct 7, 2024
cb987c4
fix const_cast by removing attempt to send client ptr to log event. l…
braindigitalis Oct 7, 2024
2984ed7
shut up visual c++
braindigitalis Oct 7, 2024
ce033dc
get_data size is now unused, we know the size from the vector
braindigitalis Oct 7, 2024
ac755a0
i forgor
braindigitalis Oct 7, 2024
89d549a
remove cout based logger and replace with a dpp cluster log
braindigitalis Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,12 @@
"khanda",
"oclock",
"moai",
"xbps"
"xbps",
"chacha20",
"chacha",
"nullopt",
"chrono",
"ciphersuite"
],
"flagWords": [
"hte"
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ else()
add_subdirectory(library)
endif()

find_package(Filesystem)

if(DPP_USE_EXTERNAL_JSON)
# We do nothing here, we just assume it is on the include path.
# nlohmann::json's cmake stuff does all kinds of weird, and is more hassle than it's worth.
Expand All @@ -116,3 +118,7 @@ else()
# that made no sense, it seems they may have changed their parsing rules somehow.
message("-- Using bundled nlohmann::json")
endif()

if (NOT WIN32)
target_link_libraries(dpp PRIVATE std::filesystem)
endif()
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,17 @@ Other compilers may work (either newer versions of those listed above, or differ

### External Dependencies (You must install these)

* [OpenSSL](https://openssl.org/) (whichever `-dev` package comes with your OS)
* [zlib](https://zlib.net) (whichever `-dev` package comes with your OS)
* [OpenSSL](https://openssl.org/) (For HTTPS, will use whichever `-dev` package comes with your OS)
* [zlib](https://zlib.net) (For websocket compression, will use whichever `-dev` package comes with your OS)
braindigitalis marked this conversation as resolved.
Show resolved Hide resolved

#### Optional Dependencies

For voice support you require both of:
* [libopus](https://www.opus-codec.org)
* [libsodium](https://libsodium.org/)
For **voice support** you require both of:
* [libopus](https://www.opus-codec.org) (For audio encoding/decoding)
* [libsodium](https://libsodium.org/) (For transport layer encryption)
* Note that our **windows zips** come packaged with copies of both libraries - you do not need to install them yourself!

### Included Dependencies (Packaged with the library)

* [JSON for Modern C++](https://json.nlohmann.me/)
* [JSON for Modern C++](https://json.nlohmann.me/) (You can bring your own nlohmann::json into D++ by setting a CMAKE flag)
* [MLS++](https://github.com/cisco/mlspp) (This is statically compiled into the library if voice support is enabled)
247 changes: 247 additions & 0 deletions cmake/FindFilesystem.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
FindFilesystem
##############
This module supports the C++17 standard library's filesystem utilities. Use the
:imp-target:`std::filesystem` imported target to
Options
*******
The ``COMPONENTS`` argument to this module supports the following values:
.. find-component:: Experimental
:name: fs.Experimental
Allows the module to find the "experimental" Filesystem TS version of the
Filesystem library. This is the library that should be used with the
``std::experimental::filesystem`` namespace.
.. find-component:: Final
:name: fs.Final
Finds the final C++17 standard version of the filesystem library.
If no components are provided, behaves as if the
:find-component:`fs.Final` component was specified.
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
Imported Targets
****************
.. imp-target:: std::filesystem
The ``std::filesystem`` imported target is defined when any requested
version of the C++ filesystem library has been found, whether it is
*Experimental* or *Final*.
If no version of the filesystem library is available, this target will not
be defined.
.. note::
This target has ``cxx_std_17`` as an ``INTERFACE``
:ref:`compile language standard feature <req-lang-standards>`. Linking
to this target will automatically enable C++17 if no later standard
version is already required on the linking target.
.. _fs.variables:
Variables
*********
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
filesystem library was found, otherwise ``FALSE``.
.. variable:: CXX_FILESYSTEM_HAVE_FS
Set to ``TRUE`` when a filesystem header was found.
.. variable:: CXX_FILESYSTEM_HEADER
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
found.
.. variable:: CXX_FILESYSTEM_NAMESPACE
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
depending on whether :find-component:`fs.Final` or
:find-component:`fs.Experimental` was found.
Examples
********
Using `find_package(Filesystem)` with no component arguments:
.. code-block:: cmake
find_package(Filesystem REQUIRED)
add_executable(my-program main.cpp)
target_link_libraries(my-program PRIVATE std::filesystem)
#]=======================================================================]


if(TARGET std::filesystem)
# This module has already been processed. Don't do it again.
return()
endif()

cmake_minimum_required(VERSION 3.10)

include(CMakePushCheckState)
include(CheckIncludeFileCXX)

# If we're not cross-compiling, try to run test executables.
# Otherwise, assume that compile + link is a sufficient check.
if(CMAKE_CROSSCOMPILING)
include(CheckCXXSourceCompiles)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_compiles("${code}" ${var})
endmacro()
else()
include(CheckCXXSourceRuns)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_runs("${code}" ${var})
endmacro()
endif()

cmake_push_check_state()

set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})

# All of our tests required C++17 or later
set(CMAKE_CXX_STANDARD 17)

# Normalize and check the component list we were given
set(want_components ${Filesystem_FIND_COMPONENTS})
if(Filesystem_FIND_COMPONENTS STREQUAL "")
set(want_components Final)
endif()

# Warn on any unrecognized components
set(extra_components ${want_components})
list(REMOVE_ITEM extra_components Final Experimental)
foreach(component IN LISTS extra_components)
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
endforeach()

# Detect which of Experimental and Final we should look for
set(find_experimental TRUE)
set(find_final TRUE)
if(NOT "Final" IN_LIST want_components)
set(find_final FALSE)
endif()
if(NOT "Experimental" IN_LIST want_components)
set(find_experimental FALSE)
endif()

if(find_final)
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
if(_CXX_FILESYSTEM_HAVE_HEADER)
# We found the non-experimental header. Don't bother looking for the
# experimental one.
set(find_experimental FALSE)
endif()
else()
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
endif()

if(find_experimental)
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
else()
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
endif()

if(_CXX_FILESYSTEM_HAVE_HEADER)
set(_have_fs TRUE)
set(_fs_header filesystem)
set(_fs_namespace std::filesystem)
set(_is_experimental FALSE)
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
set(_have_fs TRUE)
set(_fs_header experimental/filesystem)
set(_fs_namespace std::experimental::filesystem)
set(_is_experimental TRUE)
else()
set(_have_fs FALSE)
endif()

set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")

set(_found FALSE)

if(CXX_FILESYSTEM_HAVE_FS)
# We have some filesystem library available. Do link checks
string(CONFIGURE [[
#include <cstdlib>
#include <@CXX_FILESYSTEM_HEADER@>

int main() {
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
printf("%s", cwd.c_str());
return EXIT_SUCCESS;
}
]] code @ONLY)

# Check a simple filesystem program without any linker flags
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)

set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})

if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
# Add the libstdc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
# Try the libc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
endif()
endif()

if(can_link)
add_library(std::filesystem INTERFACE IMPORTED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
set(_found TRUE)

if(CXX_FILESYSTEM_NO_LINK_NEEDED)
# Nothing to add...
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
endif()
endif()
endif()

cmake_pop_check_state()

set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)

if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
endif()
7 changes: 7 additions & 0 deletions docpages/advanced_reference/unit_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export TEST_USER_ID="826535422381391913"
export TEST_EVENT_ID="909928577951203360"
```

You may also optionally set:
```bash
export TEST_DATA_DIR="/path/to/test/data"
```
If you wish to have test data (Robot.pcm etc) in a different location than two directories above the unit test program. If you do not specify
this environment variable the default will be used.

Then, after cloning and building DPP, run `cd build && ctest -VV` for unit test cases.

If you do not specify the `DPP_UNIT_TEST_TOKEN` environment variable, a subset of the tests will run which do not require discord connectivity.
57 changes: 57 additions & 0 deletions docpages/advanced_reference/voice_model.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
\page voice-model Voice Model

# High Level Summary

Discord's audio system consists of several layers and inter-related systems as shown in the flow chart below.

At the top level, connecting to a voice server requires the library to request the details of a voice server from Discord via the websocket for the shard where the
server is located. Performing this request will make Discord reply with a websocket URI and an ephemeral token (not the bot token) which are used to establish an
initial connection to this secondary websocket. Every connection to a voice channel creates a separate secondary websocket.

Once connected to this websocket, the library negotiates which protocols it supports and what encryption schemes to use. If you enabled DAVE (Discord's end-to-end
encryption scheme) this is negotiated first. An MLS (message layer security) group is joined or created. If you did not enable DAVE, this step is bypassed.

The secondary websocket then gives the library a shared encryption secret and the hostname of an RTP server, which is used to encrypt RTP packets using libsodium.
This is stored for later.

The next step is to send an initial packet to the RTP server so that the library can detect the public IP where the bot is running. Once the RTP server replies,
the bot may tell the websocket what encryption protocols it is going to use to encrypt the RTP packet contents (leaving the RTP header somwhat intact).

The library is now in an initialised state and will accept method calls for `send_audio_raw()` and `send_audio_opus()`. If you send raw audio, it will first be
encoded as OPUS using libopus, and potentially repacketized to fit into UDP packets, with larger streams being split into multiple smaller packets that are scheduled
to be sent in the future.

If at this point DAVE is enabled, the contents of the OPUS encoded audio are encrypted using the AES 128 bit AEAD cipher and using the bot's MLS ratchet, derived
during the MLS negotiation which was carried out earlier. All valid participants in the voice channel may use their private key, and the public key derived from
their ratchets, to decrypt the OPUS audio.

Regardless of if DAVE is enabled or not, the OPUS stream (encrypted by DAVE, or "plaintext") is placed into an RTP packet, and then encrypted using the shared secret
given by the websocket, known only to you and Discord, using the xchacha20 poly1305 cipher.

The completed packet, potentially with two separate layers of encryption (one with a key only you and Discord know, and one with a key only you and participants in the
voice chat know!), plus opus encoded audio is sent on its way via UDP to the RTP server, where Discord promptly distribute it to all participants in the chat.

\image html audioframe.svg

After reading all this, go get a coffee or something, you deserve it! ☕

# Flow Diagram

\dot
digraph "Example Directory" {
graph [ranksep=1];
Expand Down Expand Up @@ -109,6 +146,26 @@ digraph "Example Directory" {
"HTTP/1.1 101 Switching Protocols" -> "discord_voice_client::handle_frame";

label = "Do the voice stuff.";

"discord_voice_client::handle_frame"-> "DAVE enabled";
"discord_voice_client::handle_frame"-> "DAVE disabled";
"DAVE disabled"->"discord_voice_client::send_audio_*()";
"discord_voice_client::send_audio_*()" -> "Dave encryption on";
"discord_voice_client::send_audio_*()" -> "Dave encryption off";
"Dave encryption on" -> "AES AEAD encryption\nof OPUS stream\nusing ratchet";
"AES AEAD encryption\nof OPUS stream\nusing ratchet" -> "SODIUM encryption (xchacha20_poly1305_aead)";
"Dave encryption off" -> "SODIUM encryption (xchacha20_poly1305_aead)";
"SODIUM encryption (xchacha20_poly1305_aead)" -> "UDP sendto";
"UDP sendto" -> "Discord RTP server";
"DAVE enabled" -> "MLS send key package";
"MLS send key package" -> "MLS receive external sender";
"MLS receive external sender" -> "MLS proposals";
"MLS proposals" -> "MLS Welcome";
"MLS proposals" -> "MLS Commit";
"MLS Commit" -> "DAVE begin transition";
"MLS Welcome" -> "DAVE begin transition";
"DAVE begin transition" -> "Dave execute transition";
"Dave execute transition" -> "discord_voice_client::send_audio_*()";
}

"Your bot" -> "guild::connect_member_voice";
Expand Down
Loading
Loading