From a51462a02944bf586b862e749ed684d85389cd8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:09:41 +0000 Subject: [PATCH 01/99] build(deps): bump ubuntu from `2e863c4` to `8a37d68` Bumps ubuntu from `2e863c4` to `8a37d68`. --- updated-dependencies: - dependency-name: ubuntu dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 103c9f7115..bd37c2e9ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30 +FROM ubuntu:noble@sha256:8a37d68f4f73ebf3d4efafbcf66379bf3728902a8038616808f04e34a9ab63ee RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libsodium-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From 392c78520934cf47709eb20a0500eca4e834b1a2 Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:43:46 -0400 Subject: [PATCH 02/99] Adding Arm-Neon implementation. --- cmake/DetectArchitecture.cmake | 9 ++- include/dpp/isa/neon.h | 116 +++++++++++++++++++++++++++++++++ include/dpp/isa_detection.h | 4 +- 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 include/dpp/isa/neon.h diff --git a/cmake/DetectArchitecture.cmake b/cmake/DetectArchitecture.cmake index 4c3a2030b5..eba403f843 100644 --- a/cmake/DetectArchitecture.cmake +++ b/cmake/DetectArchitecture.cmake @@ -3,8 +3,13 @@ include(CheckCXXSourceRuns) function(check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_FLAG INSTRUCTION_SET_INTRINSIC) set(INSTRUCTION_SET_CODE " + #if defined(__arm__) || defined(__aarch64__) + #include + #else #include #include + #endif + int main() { ${INSTRUCTION_SET_INTRINSIC}; @@ -27,12 +32,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") "AVX1?/arch:AVX?__m128i value{}#auto result = _mm_extract_epi32(value, 0)" "AVX2?/arch:AVX2?__m256i value{}#auto result = _mm256_add_epi32(__m256i{}, __m256i{})" "AVX512?/arch:AVX512?int32_t result[16]#const _mm512i& value{}#_mm512_store_si512(result, value)" + "AVX1024??uint8x16_t mask{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }#vandq_u8(mask, mask)" ) else() set(INSTRUCTION_SETS "AVX1?-mavx?__m128i value{}#auto result = _mm_extract_epi32(value, 0)" "AVX2?-mavx2?__m256i value{}#auto result = _mm256_add_epi32(__m256i{}, __m256i{})" "AVX512?-mavx512f?int32_t result[16]#const _mm512i& value{}#_mm512_store_si512(result, value)" + "AVX1024??uint8x16_t mask{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }#vandq_u8(mask, mask)" ) endif() @@ -43,7 +50,7 @@ set(AVX_TYPE "AVX0" PARENT_SCOPE) set(AVX_FLAGS "" PARENT_SCOPE) # This is only supported on x86/x64, it is completely skipped and forced to T_fallback anywhere else -if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")) +if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64") OR (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm64")) foreach(INSTRUCTION_SET IN LISTS INSTRUCTION_SETS) string(REPLACE "?" ";" CURRENT_LIST "${INSTRUCTION_SET}") diff --git a/include/dpp/isa/neon.h b/include/dpp/isa/neon.h new file mode 100644 index 0000000000..1c6a02b810 --- /dev/null +++ b/include/dpp/isa/neon.h @@ -0,0 +1,116 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#pragma once + +#if defined _MSC_VER || defined __GNUC__ || defined __clang__ + +#include +#include + +namespace dpp { + + using neon_float = float32x4_t; + + /** + * @brief A class for audio mixing operations using ARM NEON instructions. + */ + class audio_mixer { + public: + + /** + * @brief The number of 32-bit values per CPU register. + */ + inline static constexpr int32_t byte_blocks_per_register{ 4 }; + + /** + * @brief Collect a single register worth of data from data_in, apply gain and increment, and store the result in data_out. + * This version uses ARM NEON instructions. + * + * @param data_in Pointer to the input array of int32_t values. + * @param data_out Pointer to the output array of int16_t values. + * @param current_gain The gain to be applied to the elements. + * @param increment The increment value to be added to each element. + */ + inline void collect_single_register(int32_t* data_in, int16_t* data_out, float current_gain, float increment) { + neon_float gathered_values = gather_values(data_in); + neon_float gain_vector = vdupq_n_f32(current_gain); + neon_float increment_vector = vmulq_f32(vdupq_n_f32(increment), vsetq_f32(0.0f, 1.0f, 2.0f, 3.0f)); + neon_float current_samples_new = vmulq_f32(gathered_values, vaddq_f32(gain_vector, increment_vector)); + + // Clamping the values between int16_t min and max + neon_float min_val = vdupq_n_f32(static_cast(std::numeric_limits::min())); + neon_float max_val = vdupq_n_f32(static_cast(std::numeric_limits::max())); + + current_samples_new = vmaxq_f32(current_samples_new, min_val); + current_samples_new = vminq_f32(current_samples_new, max_val); + + store_values(current_samples_new, data_out); + } + + /** + * @brief Combine a register worth of elements from decoded_data and store the result in up_sampled_vector. + * This version uses ARM NEON instructions. + * + * @param up_sampled_vector Pointer to the array of int32_t values. + * @param decoded_data Pointer to the array of int16_t values. + */ + inline void combine_samples(int32_t* up_sampled_vector, const int16_t* decoded_data) { + neon_float up_sampled = gather_values(up_sampled_vector); + neon_float decoded = gather_values(decoded_data); + neon_float newValues = vaddq_f32(up_sampled, decoded); + store_values(newValues, up_sampled_vector); + } + + protected: + /** + * @brief Array for storing the values to be loaded/stored. + */ + alignas(16) float values[byte_blocks_per_register]{}; + + /** + * @brief Stores values from a 128-bit NEON vector to a storage location. + * @tparam value_type The target value type for storage. + * @param values_to_store The 128-bit NEON vector containing values to store. + * @param storage_location Pointer to the storage location. + */ + template inline void store_values(const neon_float& values_to_store, value_type* storage_location) { + vst1q_f32(values, values_to_store); + for (int64_t x = 0; x < byte_blocks_per_register; ++x) { + storage_location[x] = static_cast(values[x]); + } + } + + /** + * @brief Specialization for gathering non-float values into a NEON register. + * @tparam value_type The type of values being gathered. + * @return A NEON register containing gathered values. + */ + template inline neon_float gather_values(value_type* values_new) { + for (uint64_t x = 0; x < byte_blocks_per_register; ++x) { + values[x] = static_cast(values_new[x]); + } + return vld1q_f32(values); + } + }; + +} // namespace dpp + +#endif \ No newline at end of file diff --git a/include/dpp/isa_detection.h b/include/dpp/isa_detection.h index 2f7925efc5..54b641a7f0 100644 --- a/include/dpp/isa_detection.h +++ b/include/dpp/isa_detection.h @@ -20,7 +20,9 @@ ************************************************************************************/ #pragma once -#if AVX_TYPE == 512 +#if AVX_TYPE == 1024 + #include "isa/neon.h" +#elif AVX_TYPE == 512 #include "isa/avx512.h" #elif AVX_TYPE == 2 #include "isa/avx2.h" From 2b4fb6935993b59a4a22c384ec90c9123bef502d Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 21 Aug 2024 15:14:11 +0100 Subject: [PATCH 03/99] add armv7l --- cmake/DetectArchitecture.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/DetectArchitecture.cmake b/cmake/DetectArchitecture.cmake index eba403f843..9fac218884 100644 --- a/cmake/DetectArchitecture.cmake +++ b/cmake/DetectArchitecture.cmake @@ -1,4 +1,4 @@ -include(CheckCXXSourceRuns) +arminclude(CheckCXXSourceRuns) function(check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_FLAG INSTRUCTION_SET_INTRINSIC) @@ -50,7 +50,7 @@ set(AVX_TYPE "AVX0" PARENT_SCOPE) set(AVX_FLAGS "" PARENT_SCOPE) # This is only supported on x86/x64, it is completely skipped and forced to T_fallback anywhere else -if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64") OR (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm64")) +if ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64") OR (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "arm64") OR (${CMAKE_HOST_SYSTEM_PROCESSOR} MATCHES "armv7l")) foreach(INSTRUCTION_SET IN LISTS INSTRUCTION_SETS) string(REPLACE "?" ";" CURRENT_LIST "${INSTRUCTION_SET}") From 0d9d2dad521e5db7389ab58800ff524fa9841f47 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 21 Aug 2024 15:16:32 +0100 Subject: [PATCH 04/99] alter a cpp file to trigger code change compilation --- src/dpp/voicestate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dpp/voicestate.cpp b/src/dpp/voicestate.cpp index e421cfbd1f..f0bcbd6e9f 100644 --- a/src/dpp/voicestate.cpp +++ b/src/dpp/voicestate.cpp @@ -91,3 +91,4 @@ bool voicestate::is_suppressed() const { } } // namespace dpp + From 0e2520e8dfb5d83ce2723ffadf19bec0e4f266db Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Wed, 21 Aug 2024 14:27:45 +0000 Subject: [PATCH 05/99] fix: silly typo --- cmake/DetectArchitecture.cmake | 2 +- doxygen-awesome-css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/DetectArchitecture.cmake b/cmake/DetectArchitecture.cmake index 9fac218884..af4f84a5b7 100644 --- a/cmake/DetectArchitecture.cmake +++ b/cmake/DetectArchitecture.cmake @@ -1,4 +1,4 @@ -arminclude(CheckCXXSourceRuns) +include(CheckCXXSourceRuns) function(check_instruction_set INSTRUCTION_SET_NAME INSTRUCTION_SET_FLAG INSTRUCTION_SET_INTRINSIC) diff --git a/doxygen-awesome-css b/doxygen-awesome-css index 28ed396de1..00c7339531 160000 --- a/doxygen-awesome-css +++ b/doxygen-awesome-css @@ -1 +1 @@ -Subproject commit 28ed396de19cd3d803bcb483dceefdb6d03b1b2b +Subproject commit 00c73395317fa2cc80bd2dbe6b5a568939b81f3e From d6c20ce7f049d9b72b62db28172f01230182bf54 Mon Sep 17 00:00:00 2001 From: RealTimeChris <40668522+RealTimeChris@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:43:48 -0400 Subject: [PATCH 06/99] Adding fix to arm-neon bug. (#1226) --- include/dpp/isa/neon.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/dpp/isa/neon.h b/include/dpp/isa/neon.h index 1c6a02b810..8ee33459f8 100644 --- a/include/dpp/isa/neon.h +++ b/include/dpp/isa/neon.h @@ -52,7 +52,9 @@ namespace dpp { inline void collect_single_register(int32_t* data_in, int16_t* data_out, float current_gain, float increment) { neon_float gathered_values = gather_values(data_in); neon_float gain_vector = vdupq_n_f32(current_gain); - neon_float increment_vector = vmulq_f32(vdupq_n_f32(increment), vsetq_f32(0.0f, 1.0f, 2.0f, 3.0f)); + static constexpr float data[4] = { 0.0f, 1.0f, 2.0f, 3.0f }; + neon_float floats = vld1q_f32(data); + neon_float increment_vector = vmulq_f32(vdupq_n_f32(increment), floats)); neon_float current_samples_new = vmulq_f32(gathered_values, vaddq_f32(gain_vector, increment_vector)); // Clamping the values between int16_t min and max From 9333f30454f24df71bd9fb709523e6fa2b29e588 Mon Sep 17 00:00:00 2001 From: tandemdude <43570299+tandemdude@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:48:05 +0100 Subject: [PATCH 07/99] fix: incorrect comment --- docpages/example_code/commandhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docpages/example_code/commandhandler.cpp b/docpages/example_code/commandhandler.cpp index ea23e87529..898a1cf63a 100644 --- a/docpages/example_code/commandhandler.cpp +++ b/docpages/example_code/commandhandler.cpp @@ -35,7 +35,7 @@ int main() { /* Command description */ "A test ping command", - /* Guild id (omit for a guild command) */ + /* Guild id (omit for a global command) */ 819556414099554344 ); From 0fe5f2b90a94f79999bd03808cbf7ad9ef4a9ba7 Mon Sep 17 00:00:00 2001 From: Tracer <43095317+TracerDS@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:13:36 +0200 Subject: [PATCH 08/99] Improve compatiblity --- include/dpp/export.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/dpp/export.h b/include/dpp/export.h index e293aafccc..5ece08ef36 100644 --- a/include/dpp/export.h +++ b/include/dpp/export.h @@ -46,6 +46,7 @@ #else /* Including the library */ #ifdef _WIN32 + #include #define DPP_EXPORT __declspec(dllimport) #else #define DPP_EXPORT @@ -116,11 +117,13 @@ extern bool DPP_EXPORT validate_configuration(); } #ifndef _WIN32 - #define SOCKET int + #ifndef SOCKET + #define SOCKET int + #endif #else - #ifndef NOMINMAX - #define NOMINMAX - #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif #include #endif From e7a895c82a385a0edcbb3cc876de69360adae10d Mon Sep 17 00:00:00 2001 From: Tracer <43095317+TracerDS@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:50:31 +0200 Subject: [PATCH 09/99] Updated socket --- include/dpp/export.h | 7 +------ include/dpp/socket.h | 12 +++++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/dpp/export.h b/include/dpp/export.h index 5ece08ef36..7895e79ec4 100644 --- a/include/dpp/export.h +++ b/include/dpp/export.h @@ -46,7 +46,6 @@ #else /* Including the library */ #ifdef _WIN32 - #include #define DPP_EXPORT __declspec(dllimport) #else #define DPP_EXPORT @@ -116,11 +115,7 @@ extern bool DPP_EXPORT validate_configuration(); } -#ifndef _WIN32 - #ifndef SOCKET - #define SOCKET int - #endif -#else +#ifdef _WIN32 #ifndef NOMINMAX #define NOMINMAX #endif diff --git a/include/dpp/socket.h b/include/dpp/socket.h index 04d1080035..d94914b35a 100644 --- a/include/dpp/socket.h +++ b/include/dpp/socket.h @@ -1,18 +1,16 @@ #pragma once -#ifndef _WIN32 -#ifndef SOCKET -#define SOCKET int -#endif -#endif - namespace dpp { /** * @brief Represents a socket file descriptor. * This is used to ensure parity between windows and unix-like systems. */ - typedef SOCKET socket; +#ifndef _WIN32 + using socket = int; +#else + using socket = SOCKET; +#endif } // namespace dpp #ifndef SOCKET_ERROR From a1d4d4ca9cf918beaac03d054d10a5eb7d321f2d Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Fri, 30 Aug 2024 04:18:10 -0400 Subject: [PATCH 10/99] fix: fix guild_member::get_avatar_url() (#1230) (#1231) --- src/dpp/guild.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/guild.cpp b/src/dpp/guild.cpp index 2e0729e7b2..a4040e2a99 100644 --- a/src/dpp/guild.cpp +++ b/src/dpp/guild.cpp @@ -217,7 +217,7 @@ void from_json(const nlohmann::json& j, guild_member& gm) { std::string guild_member::get_avatar_url(uint16_t size, const image_type format, bool prefer_animated) const { if (this->guild_id && this->user_id && !this->avatar.to_string().empty()) { return utility::cdn_endpoint_url_hash({ i_jpg, i_png, i_webp, i_gif }, - "guilds/" + std::to_string(this->guild_id) + "/" + std::to_string(this->user_id), this->avatar.to_string(), + "guilds/" + std::to_string(this->guild_id) + "/users/" + std::to_string(this->user_id) + "/avatars", this->avatar.to_string(), format, size, prefer_animated, has_animated_guild_avatar()); } else { return std::string(); From 45a4ae6f3faa36dc5e1b8557716745dee8fb934f Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Fri, 30 Aug 2024 05:38:43 -0400 Subject: [PATCH 11/99] fix: fix requests fizzling if the response doesn't contain Content-Length (#1232) --- src/dpp/httpsclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/httpsclient.cpp b/src/dpp/httpsclient.cpp index 29598cd375..5d56f43a5c 100644 --- a/src/dpp/httpsclient.cpp +++ b/src/dpp/httpsclient.cpp @@ -284,7 +284,7 @@ bool https_client::handle_buffer(std::string &buffer) case HTTPS_CONTENT: body += buffer; buffer.clear(); - if (body.length() >= content_length) { + if (content_length == ULLONG_MAX || body.length() >= content_length) { state = HTTPS_DONE; this->close(); return false; From de9d0e61a6a1e2bad4fc27ba6ec8b64ac681df17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:08 +0000 Subject: [PATCH 12/99] build(deps): bump docker/build-push-action from 6.2.0 to 6.7.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.2.0 to 6.7.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/15560696de535e4014efeff63c48f16952e52dd1...5cd11c3a4ced054e52742c5fd54dca954e0edd85) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 40fe4e9d06..3c5b5c04c3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@15560696de535e4014efeff63c48f16952e52dd1 # v6.2.0 + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6.7.0 with: push: true tags: brainboxdotcc/dpp From 6666efdf6b889731fe6cdc603403c954d77e671b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:10 +0000 Subject: [PATCH 13/99] build(deps): bump rui314/setup-mold Bumps [rui314/setup-mold](https://github.com/rui314/setup-mold) from 2e332a0b602c2fc65d2d3995941b1b29a5f554a0 to 0bf4f07ef9048ec62a45f9dbf2f098afa49695f0. - [Commits](https://github.com/rui314/setup-mold/compare/2e332a0b602c2fc65d2d3995941b1b29a5f554a0...0bf4f07ef9048ec62a45f9dbf2f098afa49695f0) --- updated-dependencies: - dependency-name: rui314/setup-mold dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95cf307c37..7f236947aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: - name: Setup mold if: ${{ matrix.cfg.mold == 'yes' }} - uses: rui314/setup-mold@2e332a0b602c2fc65d2d3995941b1b29a5f554a0 # v1 + uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 - name: Generate CMake run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release ${{matrix.cfg.cmake-flags}} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ce56c8c98a..f5883fc789 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -58,7 +58,7 @@ jobs: # Prefix the list here with "+" to use these queries and those in the config file. - name: Setup mold - uses: rui314/setup-mold@2e332a0b602c2fc65d2d3995941b1b29a5f554a0 + uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 - name: Build run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release && cmake --build build -j4 From 04b5be33c6ce1efe62c933415bc9b6ed813bfcb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:11 +0000 Subject: [PATCH 14/99] build(deps): bump docker/setup-qemu-action from 3.0.0 to 3.2.0 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.0.0 to 3.2.0. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/68827325e0b33c7199eb31dd4e31fbe9023e06e3...49b3bc8e6bdd4a60e6116a5414239cba5943d3cf) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 40fe4e9d06..f304848130 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -28,7 +28,7 @@ jobs: - name: Set up QEMU - uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 From 8d16653c5569441d28ad3b1b13f4a065551dc737 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:14 +0000 Subject: [PATCH 15/99] build(deps): bump docker/login-action from 3.1.0 to 3.3.0 Bumps [docker/login-action](https://github.com/docker/login-action) from 3.1.0 to 3.3.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/e92390c5fb421da1463c202d546fed0ec5c39f20...9780b0c442fbb1117ed29e0efdff1e18412f7567) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 40fe4e9d06..92c5322111 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -34,13 +34,13 @@ jobs: uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - name: Login to DockerHub - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ghcr.io username: ${{ github.repository_owner }} From e02c66de1930b762af750b916797494681634078 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:39:15 +0000 Subject: [PATCH 16/99] build(deps): bump docker/setup-buildx-action from 3.3.0 to 3.6.1 Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.3.0 to 3.6.1. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/d70bba72b1f3fd22344832f00baa16ece964efeb...988b5a0280414f521da01fcc63a27aeeb4b104db) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 40fe4e9d06..cce02dcc04 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -31,7 +31,7 @@ jobs: uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 + uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 - name: Login to DockerHub uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 From 0959a88a963e32598934bd6cc1136fd6e48beac0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 11:57:36 +0000 Subject: [PATCH 17/99] build(deps): bump doxygen-awesome-css from `00c7339` to `4593c19` Bumps [doxygen-awesome-css](https://github.com/jothepro/doxygen-awesome-css) from `00c7339` to `4593c19`. - [Release notes](https://github.com/jothepro/doxygen-awesome-css/releases) - [Commits](https://github.com/jothepro/doxygen-awesome-css/compare/00c73395317fa2cc80bd2dbe6b5a568939b81f3e...4593c198030b6e5019aae4d9c2eeb7497f02dbf8) --- updated-dependencies: - dependency-name: doxygen-awesome-css dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- doxygen-awesome-css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen-awesome-css b/doxygen-awesome-css index 00c7339531..4593c19803 160000 --- a/doxygen-awesome-css +++ b/doxygen-awesome-css @@ -1 +1 @@ -Subproject commit 00c73395317fa2cc80bd2dbe6b5a568939b81f3e +Subproject commit 4593c198030b6e5019aae4d9c2eeb7497f02dbf8 From b90d9aa9dc8a5905e10d0e456c002034fdb35a53 Mon Sep 17 00:00:00 2001 From: Archie Date: Sun, 1 Sep 2024 22:24:35 +0100 Subject: [PATCH 18/99] feat: Started work on new encryption --- src/dpp/discordvoiceclient.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 996882e935..c28ce709b6 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -650,7 +650,7 @@ bool discord_voice_client::handle_frame(const std::string &data) { "data", { { "address", external_ip }, { "port", bound_port }, - { "mode", "xsalsa20_poly1305" } + { "mode", "aead_xchacha20_poly1305_rtpsize" } } } } @@ -765,6 +765,8 @@ void discord_voice_client::read_ready() uint8_t* encrypted_data = buffer + offset_to_data; const size_t encrypted_data_len = packet_size - offset_to_data; + if(crypto_aead_xchacha20poly1305_ietf_decrypt() != 0) + if (crypto_secretbox_open_easy(encrypted_data, encrypted_data, encrypted_data_len, nonce, secret_key)) { /* Invalid Discord RTP payload. */ @@ -1278,17 +1280,18 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet memcpy(encodedAudioData.data(), opus_packet, length); ++sequence; - const int nonceSize = 24; rtp_header header(sequence, timestamp, (uint32_t)ssrc); - int8_t nonce[nonceSize]; - std::memcpy(nonce, &header, sizeof(header)); - std::memset(nonce + sizeof(header), 0, sizeof(nonce) - sizeof(header)); - std::vector audioDataPacket(sizeof(header) + encodedAudioLength + crypto_secretbox_MACBYTES); std::memcpy(audioDataPacket.data(), &header, sizeof(header)); - crypto_secretbox_easy(audioDataPacket.data() + sizeof(header), encodedAudioData.data(), encodedAudioLength, (const unsigned char*)nonce, secret_key); + unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES]; + randombytes_buf(nonce, sizeof nonce); + + unsigned long long clen_p; + crypto_aead_xchacha20poly1305_ietf_encrypt(audioDataPacket.data() + sizeof(header), &clen_p, encodedAudioData.data(), encodedAudioLength, NULL, NULL, NULL, (const unsigned char*)nonce, secret_key); + + //crypto_secretbox_easy(audioDataPacket.data() + sizeof(header), encodedAudioData.data(), encodedAudioLength, (const unsigned char*)nonce, secret_key); this->send((const char*)audioDataPacket.data(), audioDataPacket.size(), duration); timestamp += frameSize; From 7fca986c977ebaf3d01de1d4ab6ac219df7ad983 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Thu, 19 Sep 2024 14:34:38 +0700 Subject: [PATCH 19/99] feat: initial decrypt impl, TODO: test and cleanups --- src/dpp/discordvoiceclient.cpp | 66 ++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index c28ce709b6..8ded0fcc58 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -756,44 +756,58 @@ void discord_voice_client::read_ready() /* Nonce is the RTP Header with zero padding */ uint8_t nonce[24] = { 0 }; - std::memcpy(nonce, &buffer[0], header_size); + std::memcpy(nonce, buffer, header_size); /* Get the number of CSRC in header */ const size_t csrc_count = buffer[0] & 0b0000'1111; /* Skip to the encrypted voice data */ const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; - uint8_t* encrypted_data = buffer + offset_to_data; - const size_t encrypted_data_len = packet_size - offset_to_data; - - if(crypto_aead_xchacha20poly1305_ietf_decrypt() != 0) - - if (crypto_secretbox_open_easy(encrypted_data, encrypted_data, - encrypted_data_len, nonce, secret_key)) { - /* Invalid Discord RTP payload. */ - return; + uint8_t* ciphertext = buffer + offset_to_data; + const size_t ciphertext_len = packet_size - offset_to_data; + + std::vector decrypted; + decrypted.reserve(ciphertext_len); + unsigned long long decrypted_len = 0; + + if (crypto_aead_chacha20poly1305_ietf_decrypt(decrypted.data(), &decrypted_len, + NULL, + ciphertext, ciphertext_len, + NULL, + NULL, + nonce, secret_key) != 0) { + /* Invalid Discord RTP payload. */ + return; } - const uint8_t* decrypted_data = encrypted_data; - size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; - if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - /* Skip the RTP Extensions */ - size_t ext_len = 0; - { - uint16_t ext_len_in_words; - memcpy(&ext_len_in_words, &decrypted_data[2], sizeof(uint16_t)); - ext_len_in_words = ntohs(ext_len_in_words); - ext_len = sizeof(uint32_t) * ext_len_in_words; - } - constexpr size_t ext_header_len = sizeof(uint16_t) * 2; - decrypted_data += ext_header_len + ext_len; - decrypted_data_len -= ext_header_len + ext_len; - } + // if(crypto_aead_xchacha20poly1305_ietf_decrypt() != 0) + + // if (crypto_secretbox_open_easy(encrypted_data, encrypted_data, + // encrypted_data_len, nonce, secret_key)) { + // /* Invalid Discord RTP payload. */ + // return; + // } + + // const uint8_t* decrypted_data = encrypted_data; + // size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; + // if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { + // /* Skip the RTP Extensions */ + // size_t ext_len = 0; + // { + // uint16_t ext_len_in_words; + // memcpy(&ext_len_in_words, &decrypted_data[2], sizeof(uint16_t)); + // ext_len_in_words = ntohs(ext_len_in_words); + // ext_len = sizeof(uint32_t) * ext_len_in_words; + // } + // constexpr size_t ext_header_len = sizeof(uint16_t) * 2; + // decrypted_data += ext_header_len + ext_len; + // decrypted_data_len -= ext_header_len + ext_len; + // } /* * We're left with the decrypted, opus-encoded data. * Park the payload and decode on the voice courier thread. */ - vp.vr->audio_data.assign(decrypted_data, decrypted_data + decrypted_data_len); + vp.vr->audio_data.assign(decrypted.begin(), decrypted.end()); { std::lock_guard lk(voice_courier_shared_state.mtx); From 684d4e9abd0ce43225274d15e33bfc16f71ff168 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Fri, 20 Sep 2024 03:29:43 +0700 Subject: [PATCH 20/99] feat: progress?? --- include/dpp/discordvoiceclient.h | 11 ++++ src/dpp/discordvoiceclient.cpp | 103 +++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 07e4364483..8ed58107d8 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -346,6 +346,17 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ uint32_t timestamp; + /** + * @brief Each packet should have a nonce, a 32-bit incremental + * integer value appended to payload. + * + * We should keep track of this value and increment it for each + * packet sent. + * + * Current initial value is hardcoded to 1. + */ + uint32_t packet_nonce; + /** * @brief Last sent packet high-resolution timestamp */ diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 8ded0fcc58..e6004ff584 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -20,6 +20,7 @@ * ************************************************************************************/ +#include #include #ifdef _WIN32 #include @@ -316,6 +317,7 @@ discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _ch secret_key(nullptr), sequence(0), timestamp(0), + packet_nonce(1), last_timestamp(std::chrono::high_resolution_clock::now()), sending(false), tracks(0), @@ -593,6 +595,9 @@ bool discord_voice_client::handle_frame(const std::string &data) rdy.voice_channel_id = this->channel_id; creator->on_voice_ready.call(rdy); } + + /* Reset packet_nonce */ + packet_nonce = 1; } break; /* Voice ready */ @@ -754,30 +759,30 @@ void discord_voice_client::read_ready() std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); vp.timestamp = ntohl(vp.timestamp); - /* Nonce is the RTP Header with zero padding */ - uint8_t nonce[24] = { 0 }; - std::memcpy(nonce, buffer, header_size); + // nonce is 4 byte at the end of payload now + // change accordingly + // /* Nonce is the RTP Header with zero padding */ + // uint8_t nonce[24] = { 0 }; + // std::memcpy(nonce, buffer, header_size); - /* Get the number of CSRC in header */ - const size_t csrc_count = buffer[0] & 0b0000'1111; - /* Skip to the encrypted voice data */ - const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; - uint8_t* ciphertext = buffer + offset_to_data; - const size_t ciphertext_len = packet_size - offset_to_data; + // /* Get the number of CSRC in header */ + // const size_t csrc_count = buffer[0] & 0b0000'1111; + // /* Skip to the encrypted voice data */ + // const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; + // uint8_t* ciphertext = buffer + offset_to_data; + // const size_t ciphertext_len = packet_size - offset_to_data; - std::vector decrypted; - decrypted.reserve(ciphertext_len); unsigned long long decrypted_len = 0; - if (crypto_aead_chacha20poly1305_ietf_decrypt(decrypted.data(), &decrypted_len, - NULL, - ciphertext, ciphertext_len, - NULL, - NULL, - nonce, secret_key) != 0) { - /* Invalid Discord RTP payload. */ - return; - } + // if (crypto_aead_xchacha20poly1305_ietf_decrypt(buffer, &decrypted_len, + // NULL, + // ciphertext, ciphertext_len, + // NULL, + // NULL, + // nonce, secret_key) != 0) { + // /* Invalid Discord RTP payload. */ + // return; + // } // if(crypto_aead_xchacha20poly1305_ietf_decrypt() != 0) @@ -807,7 +812,7 @@ void discord_voice_client::read_ready() * We're left with the decrypted, opus-encoded data. * Park the payload and decode on the voice courier thread. */ - vp.vr->audio_data.assign(decrypted.begin(), decrypted.end()); + vp.vr->audio_data.assign(buffer, buffer + decrypted_len); { std::lock_guard lk(voice_courier_shared_state.mtx); @@ -1296,20 +1301,68 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet ++sequence; rtp_header header(sequence, timestamp, (uint32_t)ssrc); - std::vector audioDataPacket(sizeof(header) + encodedAudioLength + crypto_secretbox_MACBYTES); + /* Unencrypted header + encrypted opus packet + encrypted header as additional data + unencrypted 32 bit nonce */ + size_t packet_siz = (sizeof(header) * 2) + (encodedAudioLength + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + std::vector audioDataPacket(packet_siz); std::memcpy(audioDataPacket.data(), &header, sizeof(header)); - unsigned char nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES]; - randombytes_buf(nonce, sizeof nonce); + /* Convert to big-endian */ + uint32_t noncel = htonl(packet_nonce); + + /* 4 byte encrypt nonce padded with 20 byte NULL */ + unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { NULL }; + memcpy(encrypt_nonce, &packet_nonce, sizeof(packet_nonce)); unsigned long long clen_p; - crypto_aead_xchacha20poly1305_ietf_encrypt(audioDataPacket.data() + sizeof(header), &clen_p, encodedAudioData.data(), encodedAudioLength, NULL, NULL, NULL, (const unsigned char*)nonce, secret_key); + crypto_aead_xchacha20poly1305_ietf_encrypt(audioDataPacket.data() + sizeof(header), &clen_p, encodedAudioData.data(), encodedAudioLength, (const unsigned char *)&header, sizeof(header), NULL, (const unsigned char*)encrypt_nonce, secret_key); + + std::cout << "data[\n"; + + /*::write(STDIN_FILENO, audioDataPacket.data(), audioDataPacket.size());*/ + + std::cout << "\n]\n"; + std::cout << "size("<< audioDataPacket.size() << ")\n"; + std::cout << "clen_p("<< clen_p << ")\n"; + + // uint8_t buffer[65535] = {NULL}; + // unsigned long long decrypted_len = 0; + // if (crypto_aead_xchacha20poly1305_ietf_decrypt(buffer, &decrypted_len, + // NULL, + // audioDataPacket.data() + sizeof(header), audioDataPacket.size() - sizeof(header), + // NULL, + // NULL, + // (const unsigned char*)encrypt_nonce, secret_key) != 0) { + // std::cout << "VERIFICATION FAILED\n"; + // } + // else { + // auto pb = [](unsigned char *bin, size_t siz){ + // for (size_t i = 0; i < siz; i++) { + // printf("%d ", bin[i]); + // } + // }; + + // std::cout << "buffer[\n"; + // pb(encodedAudioData.data(), encodedAudioLength); + // std::cout<<"\n]\n"; + // std::cout << "buffer_len("<< encodedAudioLength <<")\n"; + + // std::cout << "decrypted_buffer[\n"; + // pb(buffer, decrypted_len); + // std::cout <<"\n]\n"; + // std::cout << "decrypted_len("<< decrypted_len <<")\n"; + // } //crypto_secretbox_easy(audioDataPacket.data() + sizeof(header), encodedAudioData.data(), encodedAudioLength, (const unsigned char*)nonce, secret_key); + /* Append the 4 byte nonce to the whole payload */ + std::memcpy(audioDataPacket.data() + audioDataPacket.size() - sizeof(noncel), &noncel, sizeof(noncel)); + this->send((const char*)audioDataPacket.data(), audioDataPacket.size(), duration); timestamp += frameSize; + /* Increment for next packet */ + packet_nonce++; + speak(); #else throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); From fe5b0e40dbdd21806663108d9281da20d4b1f03d Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Fri, 20 Sep 2024 04:25:27 +0700 Subject: [PATCH 21/99] feat: working encryption --- src/dpp/discordvoiceclient.cpp | 74 +++++++++++----------------------- 1 file changed, 24 insertions(+), 50 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index e6004ff584..f2236aa085 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -1301,63 +1301,37 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet ++sequence; rtp_header header(sequence, timestamp, (uint32_t)ssrc); - /* Unencrypted header + encrypted opus packet + encrypted header as additional data + unencrypted 32 bit nonce */ - size_t packet_siz = (sizeof(header) * 2) + (encodedAudioLength + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + /* Expected payload size is unencrypted header + encrypted opus packet + unencrypted 32 bit nonce */ + size_t packet_siz = sizeof(header) + (encodedAudioLength + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + std::vector audioDataPacket(packet_siz); + + /* Set RTP header */ std::memcpy(audioDataPacket.data(), &header, sizeof(header)); - /* Convert to big-endian */ + /* Convert nonce to big-endian */ uint32_t noncel = htonl(packet_nonce); - /* 4 byte encrypt nonce padded with 20 byte NULL */ - unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { NULL }; - memcpy(encrypt_nonce, &packet_nonce, sizeof(packet_nonce)); - - unsigned long long clen_p; - crypto_aead_xchacha20poly1305_ietf_encrypt(audioDataPacket.data() + sizeof(header), &clen_p, encodedAudioData.data(), encodedAudioLength, (const unsigned char *)&header, sizeof(header), NULL, (const unsigned char*)encrypt_nonce, secret_key); - - std::cout << "data[\n"; - - /*::write(STDIN_FILENO, audioDataPacket.data(), audioDataPacket.size());*/ - - std::cout << "\n]\n"; - std::cout << "size("<< audioDataPacket.size() << ")\n"; - std::cout << "clen_p("<< clen_p << ")\n"; - - // uint8_t buffer[65535] = {NULL}; - // unsigned long long decrypted_len = 0; - // if (crypto_aead_xchacha20poly1305_ietf_decrypt(buffer, &decrypted_len, - // NULL, - // audioDataPacket.data() + sizeof(header), audioDataPacket.size() - sizeof(header), - // NULL, - // NULL, - // (const unsigned char*)encrypt_nonce, secret_key) != 0) { - // std::cout << "VERIFICATION FAILED\n"; - // } - // else { - // auto pb = [](unsigned char *bin, size_t siz){ - // for (size_t i = 0; i < siz; i++) { - // printf("%d ", bin[i]); - // } - // }; - - // std::cout << "buffer[\n"; - // pb(encodedAudioData.data(), encodedAudioLength); - // std::cout<<"\n]\n"; - // std::cout << "buffer_len("<< encodedAudioLength <<")\n"; - - // std::cout << "decrypted_buffer[\n"; - // pb(buffer, decrypted_len); - // std::cout <<"\n]\n"; - // std::cout << "decrypted_len("<< decrypted_len <<")\n"; - // } - - //crypto_secretbox_easy(audioDataPacket.data() + sizeof(header), encodedAudioData.data(), encodedAudioLength, (const unsigned char*)nonce, secret_key); - - /* Append the 4 byte nonce to the whole payload */ + /* 24 byte is needed for encrypting, discord just want 4 byte so just fill up the rest with null */ + unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { '\0' }; + memcpy(encrypt_nonce, &noncel, sizeof(noncel)); + + /* Execute */ + crypto_aead_xchacha20poly1305_ietf_encrypt( + audioDataPacket.data() + sizeof(header), + nullptr, + encodedAudioData.data(), + encodedAudioLength, + reinterpret_cast(&header), + sizeof(header), + nullptr, + (const unsigned char*)encrypt_nonce, + secret_key); + + /* Append the 4 byte nonce to the resulting payload */ std::memcpy(audioDataPacket.data() + audioDataPacket.size() - sizeof(noncel), &noncel, sizeof(noncel)); - this->send((const char*)audioDataPacket.data(), audioDataPacket.size(), duration); + this->send(reinterpret_cast(audioDataPacket.data()), audioDataPacket.size(), duration); timestamp += frameSize; /* Increment for next packet */ From b002e89378722a17e11915da0f55f91e42768a58 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Fri, 20 Sep 2024 06:11:30 +0700 Subject: [PATCH 22/99] fix: static cast this --- src/dpp/discordvoiceclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index f2236aa085..8b0dba0bca 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -1325,7 +1325,7 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet reinterpret_cast(&header), sizeof(header), nullptr, - (const unsigned char*)encrypt_nonce, + static_cast(encrypt_nonce), secret_key); /* Append the 4 byte nonce to the resulting payload */ From 12093ccbac6e2c426e146474c745fe474a64a35d Mon Sep 17 00:00:00 2001 From: Amber Ehrlich Date: Fri, 20 Sep 2024 13:07:11 -0400 Subject: [PATCH 23/99] ci: fix mac xcode version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f236947aa..526ed0ef25 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,7 +124,7 @@ jobs: fail-fast: false # Don't fail everything if one fails. We want to test each OS/Compiler individually matrix: cfg: - - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-16, cmake-flags: '', xcode-version: '16.0-beta' } + - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-16, cmake-flags: '', xcode-version: '16.0.0' } - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-15, cmake-flags: '', xcode-version: '15.3' } - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-14, cmake-flags: '', xcode-version: '14.3.1' } steps: From c3fbf622b591ec96756cb4581ea04979ab626821 Mon Sep 17 00:00:00 2001 From: Matteo Lorenzo Nasci Date: Fri, 20 Sep 2024 19:54:14 +0200 Subject: [PATCH 24/99] fix: Added missing include to awaitable.h (#1243) --- include/dpp/coro/awaitable.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dpp/coro/awaitable.h b/include/dpp/coro/awaitable.h index 9a6836b863..e8974c0a88 100644 --- a/include/dpp/coro/awaitable.h +++ b/include/dpp/coro/awaitable.h @@ -39,6 +39,7 @@ struct awaitable_dummy { // Do not include as coro.h includes or depending on clang version #include +#include #include #include #include From 7784e03bcd0385360319a289cc600cb41849e632 Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:44:12 -0400 Subject: [PATCH 25/99] ci: add clang-19-libc++ as manual install (#1245) --- .github/workflows/ci.yml | 68 ++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 526ed0ef25..4037de4c00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,10 +31,10 @@ jobs: permissions: contents: write concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.cfg.arch }}-(${{ matrix.cfg.cpp-version }}) + group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.cfg.arch }}-(${{ matrix.cfg.cpp }}-${{ matrix.cfg.version }}) cancel-in-progress: true - name: Linux ${{matrix.cfg.arch}} (${{matrix.cfg.cpp-version}}) - runs-on: ${{matrix.cfg.os}} + name: Linux ${{ matrix.cfg.arch }} (${{ matrix.cfg.cpp }}-${{ matrix.cfg.version }}${{ matrix.cfg.name-extra }}) + runs-on: ${{ matrix.cfg.os }} strategy: fail-fast: false # Don't fail everything if one fails. We want to test each OS/Compiler individually matrix: @@ -42,26 +42,27 @@ jobs: # arm7hf is a self-hosted docker-based runner at Brainbox.cc. Raspberry Pi 4, 8gb 4-core with NEON cfg: # clang++ - - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: clang-10, cpp-version: clang++-10, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-11, cpp-version: clang++-11, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-12, cpp-version: clang++-12, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-13, cpp-version: clang++-13, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-14, cpp-version: clang++-14, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-15, cpp-version: clang++-15, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-16, cpp-version: clang++-16, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-17, cpp-version: clang++-17, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-18, cpp-version: clang++-18, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: clang-10, cpp: clang++, version: 10, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-11, cpp: clang++, version: 11, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-12, cpp: clang++, version: 12, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-13, cpp: clang++, version: 13, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-14, cpp: clang++, version: 14, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: clang-15, cpp: clang++, version: 15, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-16, cpp: clang++, version: 16, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-17, cpp: clang++, version: 17, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-18, cpp: clang++, version: 18, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: '', cpp: clang++, version: 19, cmake-flags: '-DDPP_CORO=ON -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++"', cpack: 'no', ctest: 'no', mold: 'yes', llvm-install: '19.1.0', name-extra: " libc++" } # g++ - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-13, cpp-version: g++-13, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-14, cpp-version: g++-14, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-12, cpp-version: g++-12, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-11, cpp-version: g++-11, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-10, cpp-version: g++-10, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: g++-9, cpp-version: g++-9, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: g++-8, cpp-version: g++-8, cmake-flags: '', cpack: 'no', ctest: 'yes', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-13, cpp: g++, version: 13, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-14, cpp: g++, version: 14, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-12, cpp: g++, version: 12, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-11, cpp: g++, version: 11, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-22.04, package: g++-10, cpp: g++, version: 10, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: g++-9, cpp: g++, version: 9, cmake-flags: '', cpack: 'no', ctest: 'no', mold: 'yes' } + - { arch: 'amd64', concurrency: 4, os: ubuntu-20.04, package: g++-8, cpp: g++, version: 8, cmake-flags: '', cpack: 'no', ctest: 'yes', mold: 'yes' } # Self hosted - - { arch: 'arm7hf', concurrency: 4, os: [self-hosted, linux, ARM], package: g++-12, cpp-version: g++-12, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'no' } - - { arch: 'arm64', concurrency: 4, os: [self-hosted, linux, ARM64], package: g++-12, cpp-version: g++-12, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'yes' } + - { arch: 'arm7hf', concurrency: 4, os: [self-hosted, linux, ARM], package: g++-12, cpp: g++, version: 12, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'no' } + - { arch: 'arm64', concurrency: 4, os: [self-hosted, linux, ARM64], package: g++-12, cpp: g++, version: 12, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'yes' } steps: - name: Harden Runner uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 @@ -71,17 +72,24 @@ jobs: - name: Checkout D++ uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y ${{ matrix.cfg.package }} pkg-config libsodium-dev libopus-dev zlib1g-dev rpm - - name: Setup mold if: ${{ matrix.cfg.mold == 'yes' }} uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 + - name: Install LLVM + if: ${{ matrix.cfg.llvm-install != '' }} + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{ matrix.cfg.version }} all + + - name: Install apt packages + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y ${{ matrix.cfg.package }} pkg-config libsodium-dev libopus-dev zlib1g-dev rpm + - name: Generate CMake run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release ${{matrix.cfg.cmake-flags}} env: - CXX: ${{matrix.cfg.cpp-version}} + CXX: ${{ matrix.cfg.cpp }}-${{ matrix.cfg.version }} - name: Build Project run: cd build && make -j${{ matrix.cfg.concurrency }} @@ -118,15 +126,15 @@ jobs: macos: permissions: contents: write - name: macOS ${{matrix.cfg.arch}} (${{matrix.cfg.cpp-version}}) - runs-on: ${{matrix.cfg.os}} + name: macOS ${{ matrix.cfg.arch }} (${{ matrix.cfg.cpp }}-${{ matrix.cfg.version }}) + runs-on: ${{ matrix.cfg.os }} strategy: fail-fast: false # Don't fail everything if one fails. We want to test each OS/Compiler individually matrix: cfg: - - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-16, cmake-flags: '', xcode-version: '16.0.0' } - - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-15, cmake-flags: '', xcode-version: '15.3' } - - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp-version: clang++-14, cmake-flags: '', xcode-version: '14.3.1' } + - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp: clang++, version: 16, cmake-flags: '', xcode-version: '16.0.0' } + - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp: clang++, version: 15, cmake-flags: '', xcode-version: '15.3' } + - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp: clang++, version: 14, cmake-flags: '', xcode-version: '14.3.1' } steps: - name: Harden Runner uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 From d742b71db6242a3a2c93620fd284ff7a900a3fcf Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Sat, 21 Sep 2024 13:22:01 +0700 Subject: [PATCH 26/99] feat: initial receive --- src/dpp/discordvoiceclient.cpp | 247 ++++++++++++++++----------------- 1 file changed, 123 insertions(+), 124 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 8b0dba0bca..63d56be01b 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -716,145 +716,144 @@ void discord_voice_client::read_ready() uint8_t buffer[65535]; int packet_size = this->udp_recv((char*)buffer, sizeof(buffer)); - if (packet_size > 0 && (!creator->on_voice_receive.empty() || !creator->on_voice_receive_combined.empty())) { - constexpr size_t header_size = 12; - if (static_cast(packet_size) < header_size) { - /* Invalid RTP payload */ - return; - } + bool receive_handler_is_empty = creator->on_voice_receive.empty() && creator->on_voice_receive_combined.empty(); + if (packet_size <= 0 || receive_handler_is_empty) { + /* Nothing to do */ + return; + } - /* It's a "silence packet" - throw it away. */ - if (packet_size < 44) { - return; - } + constexpr size_t header_size = 12; + if (static_cast(packet_size) < header_size) { + /* Invalid RTP payload */ + return; + } - if (uint8_t payload_type = buffer[1] & 0b0111'1111; - 72 <= payload_type && payload_type <= 76) { - /* - * This is an RTCP payload. Discord is known to send - * RTCP Receiver Reports. - * - * See https://datatracker.ietf.org/doc/html/rfc3551#section-6 - */ - return; - } + /* It's a "silence packet" - throw it away. */ + if (packet_size < 44) { + return; + } - voice_payload vp{0, // seq, populate later - 0, // timestamp, populate later - std::make_unique(nullptr, std::string((char*)buffer, packet_size))}; + if (uint8_t payload_type = buffer[1] & 0b0111'1111; + 72 <= payload_type && payload_type <= 76) { + /* + * This is an RTCP payload. Discord is known to send + * RTCP Receiver Reports. + * + * See https://datatracker.ietf.org/doc/html/rfc3551#section-6 + */ + return; + } - vp.vr->voice_client = this; + voice_payload vp{0, // seq, populate later + 0, // timestamp, populate later + std::make_unique(nullptr, std::string((char*)buffer, packet_size))}; - { /* Get the User ID of the speaker */ - uint32_t speaker_ssrc; - std::memcpy(&speaker_ssrc, &buffer[8], sizeof(uint32_t)); - speaker_ssrc = ntohl(speaker_ssrc); - vp.vr->user_id = ssrc_map[speaker_ssrc]; - } + vp.vr->voice_client = this; - /* Get the sequence number of the voice UDP packet */ - std::memcpy(&vp.seq, &buffer[2], sizeof(rtp_seq_t)); - vp.seq = ntohs(vp.seq); - /* Get the timestamp of the voice UDP packet */ - std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); - vp.timestamp = ntohl(vp.timestamp); - - // nonce is 4 byte at the end of payload now - // change accordingly - // /* Nonce is the RTP Header with zero padding */ - // uint8_t nonce[24] = { 0 }; - // std::memcpy(nonce, buffer, header_size); - - // /* Get the number of CSRC in header */ - // const size_t csrc_count = buffer[0] & 0b0000'1111; - // /* Skip to the encrypted voice data */ - // const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; - // uint8_t* ciphertext = buffer + offset_to_data; - // const size_t ciphertext_len = packet_size - offset_to_data; - - unsigned long long decrypted_len = 0; - - // if (crypto_aead_xchacha20poly1305_ietf_decrypt(buffer, &decrypted_len, - // NULL, - // ciphertext, ciphertext_len, - // NULL, - // NULL, - // nonce, secret_key) != 0) { - // /* Invalid Discord RTP payload. */ - // return; - // } - - // if(crypto_aead_xchacha20poly1305_ietf_decrypt() != 0) - - // if (crypto_secretbox_open_easy(encrypted_data, encrypted_data, - // encrypted_data_len, nonce, secret_key)) { - // /* Invalid Discord RTP payload. */ - // return; - // } - - // const uint8_t* decrypted_data = encrypted_data; - // size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; - // if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - // /* Skip the RTP Extensions */ - // size_t ext_len = 0; - // { - // uint16_t ext_len_in_words; - // memcpy(&ext_len_in_words, &decrypted_data[2], sizeof(uint16_t)); - // ext_len_in_words = ntohs(ext_len_in_words); - // ext_len = sizeof(uint32_t) * ext_len_in_words; - // } - // constexpr size_t ext_header_len = sizeof(uint16_t) * 2; - // decrypted_data += ext_header_len + ext_len; - // decrypted_data_len -= ext_header_len + ext_len; - // } + { /* Get the User ID of the speaker */ + uint32_t speaker_ssrc; + std::memcpy(&speaker_ssrc, &buffer[8], sizeof(uint32_t)); + speaker_ssrc = ntohl(speaker_ssrc); + vp.vr->user_id = ssrc_map[speaker_ssrc]; + } - /* - * We're left with the decrypted, opus-encoded data. - * Park the payload and decode on the voice courier thread. - */ - vp.vr->audio_data.assign(buffer, buffer + decrypted_len); + /* Get the sequence number of the voice UDP packet */ + std::memcpy(&vp.seq, &buffer[2], sizeof(rtp_seq_t)); + vp.seq = ntohs(vp.seq); + /* Get the timestamp of the voice UDP packet */ + std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); + vp.timestamp = ntohl(vp.timestamp); + + constexpr size_t nonce_size = sizeof(uint32_t); + /* Nonce is 4 byte at the end of payload with zero padding */ + uint8_t nonce[24] = { 0 }; + std::memcpy(nonce, buffer + packet_size - nonce_size, nonce_size); + + /* Get the number of CSRC in header */ + const size_t csrc_count = buffer[0] & 0b0000'1111; + /* Skip to the encrypted voice data */ + const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; + uint8_t* ciphertext = buffer + offset_to_data; + const size_t ciphertext_len = packet_size - offset_to_data - nonce_size; + + uint8_t header[header_size] = { 0 }; + memcpy(header, buffer, header_size); + + unsigned long long decrypted_len = 0; + if (crypto_aead_xchacha20poly1305_ietf_decrypt( + buffer, &decrypted_len, + NULL, + ciphertext, ciphertext_len, + header, + header_size, + nonce, secret_key) != 0) { + /* Invalid Discord RTP payload. */ + std::cout << "INVALID PACKET\n"; + return; + } - { - std::lock_guard lk(voice_courier_shared_state.mtx); - auto& [range, payload_queue, pending_decoder_ctls, decoder] = voice_courier_shared_state.parked_voice_payloads[vp.vr->user_id]; + // const uint8_t* decrypted_data = buffer; + // size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; + // if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { + // /* Skip the RTP Extensions */ + // size_t ext_len = 0; + // { + // uint16_t ext_len_in_words; + // memcpy(&ext_len_in_words, &decrypted_data[2], sizeof(uint16_t)); + // ext_len_in_words = ntohs(ext_len_in_words); + // ext_len = sizeof(uint32_t) * ext_len_in_words; + // } + // constexpr size_t ext_header_len = sizeof(uint16_t) * 2; + // decrypted_data += ext_header_len + ext_len; + // decrypted_data_len -= ext_header_len + ext_len; + // } + + /* + * We're left with the decrypted, opus-encoded data. + * Park the payload and decode on the voice courier thread. + */ + vp.vr->audio_data.assign(buffer, buffer + decrypted_len); - if (!decoder) { - /* - * Most likely this is the first time we encounter this speaker. - * Do some initialization for not only the decoder but also the range. + { + std::lock_guard lk(voice_courier_shared_state.mtx); + auto& [range, payload_queue, pending_decoder_ctls, decoder] = voice_courier_shared_state.parked_voice_payloads[vp.vr->user_id]; + + if (!decoder) { + /* + * Most likely this is the first time we encounter this speaker. + * Do some initialization for not only the decoder but also the range. + */ + range.min_seq = vp.seq; + range.min_timestamp = vp.timestamp; + + int opus_error = 0; + decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), + &opus_decoder_destroy); + if (opus_error) { + /** + * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, + * which would otherwise conflict as every C library loves to use values from -1 downwards. */ - range.min_seq = vp.seq; - range.min_timestamp = vp.timestamp; - - int opus_error = 0; - decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), - &opus_decoder_destroy); - if (opus_error) { - /** - * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, - * which would otherwise conflict as every C library loves to use values from -1 downwards. - */ - throw dpp::voice_exception((exception_error_code)(opus_error - 10), "discord_voice_client::discord_voice_client; opus_decoder_create() failed"); - } + throw dpp::voice_exception((exception_error_code)(opus_error - 10), "discord_voice_client::discord_voice_client; opus_decoder_create() failed"); } + } - if (vp.seq < range.min_seq && vp.timestamp < range.min_timestamp) { - /* This packet arrived too late. We can only discard it. */ - return; - } - range.max_seq = vp.seq; - range.max_timestamp = vp.timestamp; - payload_queue.push(std::move(vp)); + if (vp.seq < range.min_seq && vp.timestamp < range.min_timestamp) { + /* This packet arrived too late. We can only discard it. */ + return; } + range.max_seq = vp.seq; + range.max_timestamp = vp.timestamp; + payload_queue.push(std::move(vp)); + } - voice_courier_shared_state.signal_iteration.notify_one(); + voice_courier_shared_state.signal_iteration.notify_one(); - if (!voice_courier.joinable()) { - /* Courier thread is not running, start it */ - voice_courier = std::thread(&voice_courier_loop, - std::ref(*this), - std::ref(voice_courier_shared_state)); - } + if (!voice_courier.joinable()) { + /* Courier thread is not running, start it */ + voice_courier = std::thread(&voice_courier_loop, + std::ref(*this), + std::ref(voice_courier_shared_state)); } #else throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); From a228019b52d49961102909f5d2d28b823b51022e Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Sat, 21 Sep 2024 23:07:57 +0700 Subject: [PATCH 27/99] feat: working on_voice_receive, need cleanups --- src/dpp/discordvoiceclient.cpp | 70 +++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 63d56be01b..bc9367a6a0 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -710,12 +710,29 @@ void discord_voice_client::send(const char* packet, size_t len, uint64_t duratio outbuf.emplace_back(frame); } +// static FILE *f = NULL; +// +// void init() { +// static bool i = false; +// if (i) return; +// i = true; +// +// f = fopen("report.bin", "wb"); +// } + void discord_voice_client::read_ready() { #ifdef HAVE_VOICE uint8_t buffer[65535]; int packet_size = this->udp_recv((char*)buffer, sizeof(buffer)); + std::cout << "RECEIVED SIZE("<on_voice_receive.empty() && creator->on_voice_receive_combined.empty(); if (packet_size <= 0 || receive_handler_is_empty) { /* Nothing to do */ @@ -750,8 +767,8 @@ void discord_voice_client::read_ready() vp.vr->voice_client = this; + uint32_t speaker_ssrc; { /* Get the User ID of the speaker */ - uint32_t speaker_ssrc; std::memcpy(&speaker_ssrc, &buffer[8], sizeof(uint32_t)); speaker_ssrc = ntohl(speaker_ssrc); vp.vr->user_id = ssrc_map[speaker_ssrc]; @@ -773,46 +790,55 @@ void discord_voice_client::read_ready() const size_t csrc_count = buffer[0] & 0b0000'1111; /* Skip to the encrypted voice data */ const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; + size_t total_header_len = offset_to_data; + uint8_t* ciphertext = buffer + offset_to_data; - const size_t ciphertext_len = packet_size - offset_to_data - nonce_size; + size_t ciphertext_len = packet_size - offset_to_data - nonce_size; - uint8_t header[header_size] = { 0 }; - memcpy(header, buffer, header_size); + size_t ext_len = 0; + if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { + /* Get the RTP Extensions size */ + { + uint16_t ext_len_in_words; + memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); + ext_len_in_words = ntohs(ext_len_in_words); + ext_len = sizeof(uint32_t) * ext_len_in_words; + } + constexpr size_t ext_header_len = sizeof(uint16_t) * 2; + ciphertext += ext_header_len; + ciphertext_len -= ext_header_len; + total_header_len += ext_header_len; + } - unsigned long long decrypted_len = 0; + uint8_t decrypted[65535] = { 0 }; + unsigned long long opus_packet_len = 0; if (crypto_aead_xchacha20poly1305_ietf_decrypt( - buffer, &decrypted_len, + decrypted, &opus_packet_len, NULL, ciphertext, ciphertext_len, - header, - header_size, + buffer, + total_header_len, nonce, secret_key) != 0) { /* Invalid Discord RTP payload. */ std::cout << "INVALID PACKET\n"; return; } + uint8_t *opus_packet = decrypted; + if (ext_len > 0) { + /* Skip RTP Header Extension */ + opus_packet += ext_len; + opus_packet_len -= ext_len; + } + // const uint8_t* decrypted_data = buffer; // size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; - // if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - // /* Skip the RTP Extensions */ - // size_t ext_len = 0; - // { - // uint16_t ext_len_in_words; - // memcpy(&ext_len_in_words, &decrypted_data[2], sizeof(uint16_t)); - // ext_len_in_words = ntohs(ext_len_in_words); - // ext_len = sizeof(uint32_t) * ext_len_in_words; - // } - // constexpr size_t ext_header_len = sizeof(uint16_t) * 2; - // decrypted_data += ext_header_len + ext_len; - // decrypted_data_len -= ext_header_len + ext_len; - // } /* * We're left with the decrypted, opus-encoded data. * Park the payload and decode on the voice courier thread. */ - vp.vr->audio_data.assign(buffer, buffer + decrypted_len); + vp.vr->audio_data.assign(opus_packet, opus_packet + opus_packet_len); { std::lock_guard lk(voice_courier_shared_state.mtx); From 72938834ad119c49d8fef1aaaf197dd71046b041 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Sat, 21 Sep 2024 23:09:29 +0700 Subject: [PATCH 28/99] feat: cleanups --- src/dpp/discordvoiceclient.cpp | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index bc9367a6a0..a62cb75b8b 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -710,29 +710,12 @@ void discord_voice_client::send(const char* packet, size_t len, uint64_t duratio outbuf.emplace_back(frame); } -// static FILE *f = NULL; -// -// void init() { -// static bool i = false; -// if (i) return; -// i = true; -// -// f = fopen("report.bin", "wb"); -// } - void discord_voice_client::read_ready() { #ifdef HAVE_VOICE uint8_t buffer[65535]; int packet_size = this->udp_recv((char*)buffer, sizeof(buffer)); - std::cout << "RECEIVED SIZE("<on_voice_receive.empty() && creator->on_voice_receive_combined.empty(); if (packet_size <= 0 || receive_handler_is_empty) { /* Nothing to do */ @@ -820,7 +803,6 @@ void discord_voice_client::read_ready() total_header_len, nonce, secret_key) != 0) { /* Invalid Discord RTP payload. */ - std::cout << "INVALID PACKET\n"; return; } @@ -831,9 +813,6 @@ void discord_voice_client::read_ready() opus_packet_len -= ext_len; } - // const uint8_t* decrypted_data = buffer; - // size_t decrypted_data_len = encrypted_data_len - crypto_box_MACBYTES; - /* * We're left with the decrypted, opus-encoded data. * Park the payload and decode on the voice courier thread. From 5c45f94b051dc54951f6ccf766451a3690fa8767 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Sat, 21 Sep 2024 23:36:31 +0700 Subject: [PATCH 29/99] feat: add some comment --- src/dpp/discordvoiceclient.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index a62cb75b8b..770391d34e 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -780,7 +780,10 @@ void discord_voice_client::read_ready() size_t ext_len = 0; if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - /* Get the RTP Extensions size */ + /** + * Get the RTP Extensions size, we only get the size here because + * the extension itself is encrypted along with the opus packet + */ { uint16_t ext_len_in_words; memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); @@ -797,9 +800,14 @@ void discord_voice_client::read_ready() unsigned long long opus_packet_len = 0; if (crypto_aead_xchacha20poly1305_ietf_decrypt( decrypted, &opus_packet_len, - NULL, + nullptr, ciphertext, ciphertext_len, buffer, + /** + * Additional Data: + * The whole header (including csrc list) + + * 4 byte extension header (magic 0xBEDE + 16-bit denoting extension length) + */ total_header_len, nonce, secret_key) != 0) { /* Invalid Discord RTP payload. */ @@ -808,7 +816,7 @@ void discord_voice_client::read_ready() uint8_t *opus_packet = decrypted; if (ext_len > 0) { - /* Skip RTP Header Extension */ + /* Skip previously encrypted RTP Header Extension */ opus_packet += ext_len; opus_packet_len -= ext_len; } @@ -1326,6 +1334,7 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet nullptr, encodedAudioData.data(), encodedAudioLength, + /* The RTP Header as Additional Data */ reinterpret_cast(&header), sizeof(header), nullptr, From a0f5bc35f53ff8b81976a9cf028c92629e97cfb2 Mon Sep 17 00:00:00 2001 From: Neko-Life Date: Sat, 21 Sep 2024 23:50:01 +0700 Subject: [PATCH 30/99] feat: replace to snake case --- src/dpp/discordvoiceclient.cpp | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 770391d34e..e46d4258a0 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -1275,13 +1275,13 @@ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, return send_audio_raw((uint16_t*)packet.data(), packet.size()); } - opus_int32 encodedAudioMaxLength = (opus_int32)length; - std::vector encodedAudioData(encodedAudioMaxLength); - size_t encodedAudioLength = encodedAudioMaxLength; + opus_int32 encoded_audio_max_length = (opus_int32)length; + std::vector encoded_audio(encoded_audio_max_length); + size_t encoded_audio_length = encoded_audio_max_length; - encodedAudioLength = this->encode((uint8_t*)audio_data, length, encodedAudioData.data(), encodedAudioLength); + encoded_audio_length = this->encode((uint8_t*)audio_data, length, encoded_audio.data(), encoded_audio_length); - send_audio_opus(encodedAudioData.data(), encodedAudioLength); + send_audio_opus(encoded_audio.data(), encoded_audio_length); #else throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif @@ -1301,25 +1301,25 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { #if HAVE_VOICE - int frameSize = (int)(48 * duration * (timescale / 1000000)); - opus_int32 encodedAudioMaxLength = (opus_int32)length; - std::vector encodedAudioData(encodedAudioMaxLength); - size_t encodedAudioLength = encodedAudioMaxLength; + int frame_size = (int)(48 * duration * (timescale / 1000000)); + opus_int32 encoded_audio_max_length = (opus_int32)length; + std::vector encoded_audio(encoded_audio_max_length); + size_t encoded_audio_length = encoded_audio_max_length; - encodedAudioLength = length; - encodedAudioData.reserve(length); - memcpy(encodedAudioData.data(), opus_packet, length); + encoded_audio_length = length; + encoded_audio.reserve(length); + memcpy(encoded_audio.data(), opus_packet, length); ++sequence; rtp_header header(sequence, timestamp, (uint32_t)ssrc); /* Expected payload size is unencrypted header + encrypted opus packet + unencrypted 32 bit nonce */ - size_t packet_siz = sizeof(header) + (encodedAudioLength + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + size_t packet_siz = sizeof(header) + (encoded_audio_length + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); - std::vector audioDataPacket(packet_siz); + std::vector payload(packet_siz); /* Set RTP header */ - std::memcpy(audioDataPacket.data(), &header, sizeof(header)); + std::memcpy(payload.data(), &header, sizeof(header)); /* Convert nonce to big-endian */ uint32_t noncel = htonl(packet_nonce); @@ -1330,10 +1330,10 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet /* Execute */ crypto_aead_xchacha20poly1305_ietf_encrypt( - audioDataPacket.data() + sizeof(header), + payload.data() + sizeof(header), nullptr, - encodedAudioData.data(), - encodedAudioLength, + encoded_audio.data(), + encoded_audio_length, /* The RTP Header as Additional Data */ reinterpret_cast(&header), sizeof(header), @@ -1342,10 +1342,10 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet secret_key); /* Append the 4 byte nonce to the resulting payload */ - std::memcpy(audioDataPacket.data() + audioDataPacket.size() - sizeof(noncel), &noncel, sizeof(noncel)); + std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); - this->send(reinterpret_cast(audioDataPacket.data()), audioDataPacket.size(), duration); - timestamp += frameSize; + this->send(reinterpret_cast(payload.data()), payload.size(), duration); + timestamp += frame_size; /* Increment for next packet */ packet_nonce++; From 761b95ffc9d2ad4727b0a6631cfcd52223a77515 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 21 Sep 2024 19:02:46 +0000 Subject: [PATCH 31/99] build(deps): bump ubuntu from `8a37d68` to `dfc1087` Bumps ubuntu from `8a37d68` to `dfc1087`. --- updated-dependencies: - dependency-name: ubuntu dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bd37c2e9ef..4ea70e3e91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:8a37d68f4f73ebf3d4efafbcf66379bf3728902a8038616808f04e34a9ab63ee +FROM ubuntu:noble@sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libsodium-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From 037790d4e77bc31e2680ef8c17bb4952e4b50519 Mon Sep 17 00:00:00 2001 From: DPP VCPKG Bot Date: Sat, 21 Sep 2024 21:19:26 +0000 Subject: [PATCH 32/99] [bot] VCPKG info update [skip ci] --- vcpkg/ports/dpp/portfile.cmake | 2 +- vcpkg/ports/dpp/vcpkg.json | 2 +- vcpkg/versions/baseline.json | 2472 +++++++++++++++++--------------- vcpkg/versions/d-/dpp.json | 5 + 4 files changed, 1353 insertions(+), 1128 deletions(-) diff --git a/vcpkg/ports/dpp/portfile.cmake b/vcpkg/ports/dpp/portfile.cmake index af8d57e936..1302502ed9 100644 --- a/vcpkg/ports/dpp/portfile.cmake +++ b/vcpkg/ports/dpp/portfile.cmake @@ -2,7 +2,7 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO brainboxdotcc/DPP REF "v${VERSION}" - SHA512 4842e5e688893275e524f998bdcac1d308165a02c280f69eaa898aa8f9986a97fe687e20e3428f30777c49f1feb47905da462bbdba8c9a5ea00067e560208f91 + SHA512 0aac06f8ee67e3b4c430c9844beb6bdc3e31adebfcb2c077d18be8a8295451d70735f96dd5316d299df30b4cc4229180ffbad5095e51b49adf182290a8133a90 ) vcpkg_cmake_configure( diff --git a/vcpkg/ports/dpp/vcpkg.json b/vcpkg/ports/dpp/vcpkg.json index 5d21e83d5f..cc9cc114f3 100644 --- a/vcpkg/ports/dpp/vcpkg.json +++ b/vcpkg/ports/dpp/vcpkg.json @@ -1,6 +1,6 @@ { "name": "dpp", - "version": "10.0.30", + "version": "10.0.31", "description": "D++ Extremely Lightweight C++ Discord Library.", "homepage": "https://dpp.dev/", "license": "Apache-2.0", diff --git a/vcpkg/versions/baseline.json b/vcpkg/versions/baseline.json index 7e91f07b2a..4e4454f9ba 100644 --- a/vcpkg/versions/baseline.json +++ b/vcpkg/versions/baseline.json @@ -5,19 +5,19 @@ "port-version": 4 }, "7zip": { - "baseline": "23.01", - "port-version": 2 + "baseline": "24.08", + "port-version": 0 }, "ableton": { "baseline": "3.0.6", "port-version": 2 }, "ableton-link": { - "baseline": "3.1.1", + "baseline": "3.1.2", "port-version": 0 }, "abseil": { - "baseline": "20240116.2", + "baseline": "20240722.0", "port-version": 0 }, "absent": { @@ -25,19 +25,19 @@ "port-version": 3 }, "ace": { - "baseline": "7.1.4", + "baseline": "8.0.0", "port-version": 0 }, "acl": { - "baseline": "2.3.1", - "port-version": 2 + "baseline": "2.3.2", + "port-version": 0 }, "activemq-cpp": { "baseline": "3.9.5", - "port-version": 15 + "port-version": 16 }, "ada-url": { - "baseline": "2.7.7", + "baseline": "2.9.1", "port-version": 0 }, "ade": { @@ -80,6 +80,10 @@ "baseline": "3.10.1", "port-version": 0 }, + "aliyun-oss-cpp-sdk": { + "baseline": "1.10.0", + "port-version": 2 + }, "allegro5": { "baseline": "5.2.9.1", "port-version": 0 @@ -94,7 +98,7 @@ }, "alsa": { "baseline": "1.2.11", - "port-version": 1 + "port-version": 2 }, "amd-adl-sdk": { "baseline": "17.1", @@ -125,12 +129,12 @@ "port-version": 8 }, "angelscript": { - "baseline": "2.36.1", - "port-version": 1 + "baseline": "2.37.0", + "port-version": 0 }, "angle": { "baseline": "chromium_5414", - "port-version": 7 + "port-version": 9 }, "ankurvdev-embedresource": { "baseline": "0.0.11", @@ -153,8 +157,8 @@ "port-version": 2 }, "aom": { - "baseline": "3.8.1", - "port-version": 1 + "baseline": "3.9.1", + "port-version": 0 }, "apache-datasketches": { "baseline": "5.0.2", @@ -165,15 +169,15 @@ "port-version": 0 }, "apr": { - "baseline": "1.7.4", - "port-version": 0 + "baseline": "1.7.5", + "port-version": 1 }, "apr-util": { "baseline": "1.6.3", "port-version": 0 }, "apriltag": { - "baseline": "3.4.0", + "baseline": "3.4.2", "port-version": 0 }, "apsi": { @@ -186,11 +190,11 @@ }, "arcus": { "baseline": "4.10.0", - "port-version": 2 + "port-version": 3 }, "arg-router": { "baseline": "1.4.0", - "port-version": 0 + "port-version": 1 }, "argagg": { "baseline": "0.4.7", @@ -205,7 +209,7 @@ "port-version": 1 }, "argparse": { - "baseline": "3.0", + "baseline": "3.1", "port-version": 0 }, "args": { @@ -229,7 +233,7 @@ "port-version": 0 }, "armadillo": { - "baseline": "12.6.6", + "baseline": "12.8.4", "port-version": 1 }, "arpack-ng": { @@ -238,11 +242,11 @@ }, "arrayfire": { "baseline": "3.8.0", - "port-version": 5 + "port-version": 6 }, "arrow": { - "baseline": "16.0.0", - "port-version": 1 + "baseline": "17.0.0", + "port-version": 0 }, "arsenalgear": { "baseline": "2.1.0", @@ -253,11 +257,11 @@ "port-version": 0 }, "asio": { - "baseline": "1.30.2", + "baseline": "1.31.0", "port-version": 0 }, "asio-grpc": { - "baseline": "3.1.0", + "baseline": "3.2.0", "port-version": 0 }, "asiochan": { @@ -269,7 +273,7 @@ "port-version": 7 }, "asmjit": { - "baseline": "2023-03-25", + "baseline": "2024-06-28", "port-version": 0 }, "asmtk": { @@ -277,11 +281,15 @@ "port-version": 1 }, "assimp": { - "baseline": "5.4.0", + "baseline": "5.4.2", + "port-version": 0 + }, + "astr": { + "baseline": "0.2.1", "port-version": 0 }, "async-mqtt": { - "baseline": "5.1.1", + "baseline": "9.0.0", "port-version": 0 }, "async-simple": { @@ -333,13 +341,17 @@ "port-version": 0 }, "aubio": { - "baseline": "2022-01-26", - "port-version": 1 + "baseline": "2024-01-03", + "port-version": 0 }, "audiofile": { "baseline": "1.1.1", "port-version": 0 }, + "audit": { + "baseline": "4.0.2", + "port-version": 0 + }, "aurora": { "baseline": "2017-06-21-c75699d2a8caa726260c29b6d7a0fd35f8f28933", "port-version": 2 @@ -350,10 +362,10 @@ }, "autodock-vina": { "baseline": "1.2.5", - "port-version": 2 + "port-version": 3 }, "avcpp": { - "baseline": "2.3.0", + "baseline": "2.4.0", "port-version": 0 }, "avisynthplus": { @@ -365,7 +377,7 @@ "port-version": 0 }, "avro-cpp": { - "baseline": "1.11.3", + "baseline": "1.12.0", "port-version": 0 }, "awlib": { @@ -373,15 +385,15 @@ "port-version": 0 }, "aws-c-auth": { - "baseline": "0.7.16", + "baseline": "0.7.22", "port-version": 0 }, "aws-c-cal": { - "baseline": "0.6.10", + "baseline": "0.6.15", "port-version": 0 }, "aws-c-common": { - "baseline": "0.9.14", + "baseline": "0.9.21", "port-version": 0 }, "aws-c-compression": { @@ -393,23 +405,23 @@ "port-version": 0 }, "aws-c-http": { - "baseline": "0.8.1", + "baseline": "0.8.2", "port-version": 0 }, "aws-c-io": { - "baseline": "0.14.6", + "baseline": "0.14.18", "port-version": 0 }, "aws-c-mqtt": { - "baseline": "0.10.3", + "baseline": "0.10.5", "port-version": 0 }, "aws-c-s3": { - "baseline": "0.5.4", + "baseline": "0.5.10", "port-version": 0 }, "aws-c-sdkutils": { - "baseline": "0.1.15", + "baseline": "0.1.16", "port-version": 0 }, "aws-checksums": { @@ -417,7 +429,7 @@ "port-version": 0 }, "aws-crt-cpp": { - "baseline": "0.26.4", + "baseline": "0.26.12", "port-version": 0 }, "aws-lambda-cpp": { @@ -425,23 +437,23 @@ "port-version": 0 }, "aws-sdk-cpp": { - "baseline": "1.11.285", - "port-version": 1 + "baseline": "1.11.352", + "port-version": 0 }, "azmq": { "baseline": "2023-03-23", "port-version": 0 }, "azure-c-shared-utility": { - "baseline": "2024-03-04", + "baseline": "2024-06-24", "port-version": 1 }, "azure-core-amqp-cpp": { - "baseline": "1.0.0-beta.9", + "baseline": "1.0.0-beta.11", "port-version": 0 }, "azure-core-cpp": { - "baseline": "1.12.0", + "baseline": "1.13.0", "port-version": 0 }, "azure-core-tracing-opentelemetry-cpp": { @@ -449,20 +461,20 @@ "port-version": 3 }, "azure-data-tables-cpp": { - "baseline": "1.0.0-beta.2", + "baseline": "1.0.0-beta.4", "port-version": 0 }, "azure-identity-cpp": { - "baseline": "1.6.0", - "port-version": 1 + "baseline": "1.9.0", + "port-version": 0 }, "azure-iot-sdk-c": { - "baseline": "2024-03-04", + "baseline": "2024-08-12", "port-version": 0 }, "azure-kinect-sensor-sdk": { "baseline": "1.4.1", - "port-version": 6 + "port-version": 7 }, "azure-macro-utils-c": { "baseline": "2022-01-21", @@ -473,16 +485,16 @@ "port-version": 2 }, "azure-messaging-eventhubs-cpp": { - "baseline": "1.0.0-beta.8", + "baseline": "1.0.0-beta.9", "port-version": 0 }, "azure-security-attestation-cpp": { "baseline": "1.1.0", - "port-version": 3 + "port-version": 4 }, "azure-security-keyvault-administration-cpp": { - "baseline": "4.0.0-beta.4", - "port-version": 1 + "baseline": "4.0.0-beta.5", + "port-version": 0 }, "azure-security-keyvault-certificates-cpp": { "baseline": "4.2.1", @@ -497,39 +509,39 @@ "port-version": 1 }, "azure-storage-blobs-cpp": { - "baseline": "12.10.0", - "port-version": 1 + "baseline": "12.12.0", + "port-version": 0 }, "azure-storage-common-cpp": { - "baseline": "12.5.0", - "port-version": 1 + "baseline": "12.7.0", + "port-version": 0 }, "azure-storage-cpp": { "baseline": "7.5.0", "port-version": 6 }, "azure-storage-files-datalake-cpp": { - "baseline": "12.9.0", - "port-version": 1 + "baseline": "12.11.0", + "port-version": 0 }, "azure-storage-files-shares-cpp": { - "baseline": "12.8.0", - "port-version": 1 + "baseline": "12.10.0", + "port-version": 0 }, "azure-storage-queues-cpp": { - "baseline": "12.2.0", - "port-version": 1 + "baseline": "12.3.0", + "port-version": 0 }, "azure-uamqp-c": { - "baseline": "2024-03-04", + "baseline": "2024-08-12", "port-version": 0 }, "azure-uhttp-c": { - "baseline": "2024-03-04", + "baseline": "2024-06-24", "port-version": 0 }, "azure-umqtt-c": { - "baseline": "2024-03-04", + "baseline": "2024-06-24", "port-version": 0 }, "b64": { @@ -541,7 +553,7 @@ "port-version": 1 }, "baresip-libre": { - "baseline": "3.11.0", + "baseline": "3.15.0", "port-version": 0 }, "basisu": { @@ -553,15 +565,15 @@ "port-version": 3 }, "bddisasm": { - "baseline": "2.1.0", + "baseline": "2.1.5", "port-version": 0 }, "bde": { - "baseline": "3.124.0.0", - "port-version": 0 + "baseline": "4.8.0.0", + "port-version": 1 }, "bdwgc": { - "baseline": "8.2.6", + "baseline": "8.2.8", "port-version": 0 }, "beast": { @@ -573,8 +585,8 @@ "port-version": 0 }, "benchmark": { - "baseline": "1.8.3", - "port-version": 3 + "baseline": "1.9.0", + "port-version": 0 }, "bento4": { "baseline": "1.6.0-641", @@ -597,11 +609,15 @@ "port-version": 0 }, "bext-sml": { - "baseline": "1.1.9", + "baseline": "1.1.11", "port-version": 0 }, "bext-sml2": { - "baseline": "2024-02-02", + "baseline": "2.0.0", + "port-version": 0 + }, + "bext-text": { + "baseline": "2024-01-19", "port-version": 0 }, "bext-ut": { @@ -617,7 +633,7 @@ "port-version": 0 }, "bgfx": { - "baseline": "1.122.8595-458", + "baseline": "1.128.8786-481", "port-version": 0 }, "bigint": { @@ -637,7 +653,7 @@ "port-version": 0 }, "bitserializer": { - "baseline": "0.65", + "baseline": "0.70", "port-version": 0 }, "bitserializer-cpprestjson": { @@ -657,24 +673,24 @@ "port-version": 3 }, "bitsery": { - "baseline": "5.2.3", + "baseline": "5.2.4", "port-version": 0 }, "blake3": { - "baseline": "1.5.1", + "baseline": "1.5.4", "port-version": 0 }, "blas": { "baseline": "2023-04-14", - "port-version": 0 + "port-version": 1 }, "blaze": { "baseline": "3.8.2", "port-version": 1 }, "blend2d": { - "baseline": "2023-06-16", - "port-version": 1 + "baseline": "2024-07-08", + "port-version": 0 }, "blingfire": { "baseline": "0.1.8.1", @@ -682,7 +698,7 @@ }, "blitz": { "baseline": "2020-03-25", - "port-version": 6 + "port-version": 7 }, "bloomberg-quantum": { "baseline": "2023-02-03", @@ -693,16 +709,20 @@ "port-version": 0 }, "blpapi": { - "baseline": "3.20.2", + "baseline": "3.24.6", + "port-version": 0 + }, + "bluescarni-tanuki": { + "baseline": "2024-08-17", "port-version": 0 }, "boinc": { - "baseline": "8.0.0", + "baseline": "8.0.4", "port-version": 0 }, "bond": { - "baseline": "10.0.0", - "port-version": 3 + "baseline": "11.0.1", + "port-version": 4 }, "boolinq": { "baseline": "3.0.4", @@ -710,611 +730,611 @@ }, "boost": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-accumulators": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-algorithm": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-align": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-any": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-array": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-asio": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-assert": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-assign": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-atomic": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-beast": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-bimap": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-bind": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-build": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-callable-traits": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-charconv": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-chrono": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-circular-buffer": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-cmake": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-cobalt": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-compat": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-compatibility": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-compute": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-concept-check": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-config": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-container": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-container-hash": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-context": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-contract": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-conversion": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-convert": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-core": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-coroutine": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-coroutine2": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-crc": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-date-time": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-describe": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-detail": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-dll": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-dynamic-bitset": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-endian": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-exception": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-fiber": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-filesystem": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-flyweight": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-foreach": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-format": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-function": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-function-types": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-functional": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-fusion": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-geometry": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-gil": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-graph": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-graph-parallel": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-hana": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-headers": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-heap": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-histogram": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-hof": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-icl": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-integer": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-interprocess": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-interval": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-intrusive": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-io": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-iostreams": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-iterator": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-json": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-lambda": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-lambda2": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-leaf": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-lexical-cast": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-local-function": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-locale": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-lockfree": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-log": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-logic": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-math": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-metaparse": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-move": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-mp11": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-mpi": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-mpl": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-msm": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-multi-array": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-multi-index": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-multiprecision": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-mysql": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-nowide": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-numeric-conversion": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-odeint": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-optional": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-outcome": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-parameter": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-parameter-python": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-pfr": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-phoenix": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-poly-collection": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-polygon": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-pool": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-predef": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-preprocessor": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-process": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-program-options": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-property-map": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-property-map-parallel": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-property-tree": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-proto": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-ptr-container": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-python": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-qvm": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-random": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-range": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-ratio": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-rational": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-redis": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-regex": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-safe-numerics": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-scope": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-scope-exit": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-serialization": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-signals2": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-smart-ptr": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-sort": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-spirit": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-stacktrace": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 3 }, "boost-statechart": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-static-assert": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-static-string": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-stl-interfaces": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-system": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-test": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-thread": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-throw-exception": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-timer": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-tokenizer": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-tti": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-tuple": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-type-erasure": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-type-index": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-type-traits": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-typeof": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-ublas": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-uninstall": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-units": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-unordered": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-url": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-utility": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-uuid": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-variant": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-variant2": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-vcpkg-helpers": { "baseline": "1.84.0", @@ -1322,31 +1342,31 @@ }, "boost-vmd": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-wave": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 2 }, "boost-winapi": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-xpressive": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boost-yap": { "baseline": "1.85.0", - "port-version": 0 + "port-version": 1 }, "boringssl": { "baseline": "2023-10-13", "port-version": 0 }, "botan": { - "baseline": "3.3.0", - "port-version": 0 + "baseline": "3.5.0", + "port-version": 1 }, "box2d": { "baseline": "2.4.1", @@ -1354,11 +1374,11 @@ }, "braft": { "baseline": "2021-26-04", - "port-version": 4 + "port-version": 5 }, "breakpad": { "baseline": "2023-06-01", - "port-version": 0 + "port-version": 2 }, "brigand": { "baseline": "1.3.0", @@ -1369,8 +1389,8 @@ "port-version": 1 }, "brpc": { - "baseline": "1.6.1", - "port-version": 3 + "baseline": "1.10.0", + "port-version": 0 }, "brunocodutra-metal": { "baseline": "2.1.4", @@ -1389,12 +1409,12 @@ "port-version": 0 }, "buck-yeh-bux": { - "baseline": "1.6.8", - "port-version": 1 + "baseline": "1.8.0", + "port-version": 0 }, "buck-yeh-bux-mariadb-client": { - "baseline": "1.0.3", - "port-version": 1 + "baseline": "1.0.4", + "port-version": 0 }, "buck-yeh-bux-sqlite": { "baseline": "1.0.1", @@ -1402,7 +1422,7 @@ }, "bullet3": { "baseline": "3.25", - "port-version": 1 + "port-version": 2 }, "bustache": { "baseline": "1.1.0", @@ -1413,8 +1433,8 @@ "port-version": 4 }, "bxzstr": { - "baseline": "1.2.0", - "port-version": 1 + "baseline": "1.2.2", + "port-version": 0 }, "byte-lite": { "baseline": "0.3.0", @@ -1422,10 +1442,10 @@ }, "bzip2": { "baseline": "1.0.8", - "port-version": 5 + "port-version": 6 }, "c-ares": { - "baseline": "1.28.1", + "baseline": "1.33.1", "port-version": 0 }, "c-dbg-macro": { @@ -1433,7 +1453,7 @@ "port-version": 0 }, "c4core": { - "baseline": "0.1.11", + "baseline": "0.2.1", "port-version": 0 }, "c89stringutils": { @@ -1445,11 +1465,11 @@ "port-version": 0 }, "cachelib": { - "baseline": "2024.05.06.00", + "baseline": "2024.07.15.00", "port-version": 0 }, "caf": { - "baseline": "0.19.3", + "baseline": "1.0.1", "port-version": 0 }, "caffe2": { @@ -1461,8 +1481,8 @@ "port-version": 1 }, "cairomm": { - "baseline": "1.17.1", - "port-version": 1 + "baseline": "1.18.0", + "port-version": 0 }, "calceph": { "baseline": "4.0.0", @@ -1481,20 +1501,20 @@ "port-version": 0 }, "capstone": { - "baseline": "5.0.1", - "port-version": 1 + "baseline": "5.0.3", + "port-version": 0 }, "cargs": { - "baseline": "1.1.0", + "baseline": "1.2.0", "port-version": 0 }, "cartographer": { "baseline": "1.0.0", - "port-version": 5 + "port-version": 6 }, "casclib": { - "baseline": "2021-11-16", - "port-version": 1 + "baseline": "2024-06-05", + "port-version": 0 }, "catch": { "baseline": "alias", @@ -1505,7 +1525,7 @@ "port-version": 2 }, "catch2": { - "baseline": "3.6.0", + "baseline": "3.7.1", "port-version": 0 }, "cblas": { @@ -1522,18 +1542,22 @@ }, "ccfits": { "baseline": "2.5", - "port-version": 11 + "port-version": 13 }, "cctag": { - "baseline": "1.0.2", - "port-version": 6 + "baseline": "1.0.4", + "port-version": 0 }, "cctz": { "baseline": "2.4", "port-version": 0 }, + "cddlib": { + "baseline": "0.94m", + "port-version": 0 + }, "cdt": { - "baseline": "1.4.0", + "baseline": "1.4.1", "port-version": 0 }, "celero": { @@ -1542,7 +1566,7 @@ }, "cello": { "baseline": "2019-07-23", - "port-version": 3 + "port-version": 4 }, "cereal": { "baseline": "1.3.2", @@ -1554,22 +1578,22 @@ }, "cfitsio": { "baseline": "3.49", - "port-version": 5 + "port-version": 6 }, "cgal": { "baseline": "5.6.1", - "port-version": 0 + "port-version": 1 }, "cgicc": { "baseline": "3.2.20", - "port-version": 0 + "port-version": 1 }, "cglm": { "baseline": "0.9.4", "port-version": 0 }, "cgltf": { - "baseline": "1.13", + "baseline": "1.14", "port-version": 0 }, "cgns": { @@ -1602,7 +1626,7 @@ }, "chmlib": { "baseline": "0.40", - "port-version": 7 + "port-version": 8 }, "chromaprint": { "baseline": "1.5.1", @@ -1610,7 +1634,7 @@ }, "chromium-base": { "baseline": "86.0.4199.1", - "port-version": 5 + "port-version": 6 }, "chronoengine": { "baseline": "8.0.0", @@ -1621,11 +1645,11 @@ "port-version": 0 }, "cimg": { - "baseline": "3.3.2", + "baseline": "3.4.1", "port-version": 0 }, "cista": { - "baseline": "0.14", + "baseline": "0.15", "port-version": 0 }, "cityhash": { @@ -1637,7 +1661,7 @@ "port-version": 2 }, "cjson": { - "baseline": "1.7.17", + "baseline": "1.7.18", "port-version": 0 }, "clamav": { @@ -1670,15 +1694,15 @@ }, "clfft": { "baseline": "2.12.2", - "port-version": 6 + "port-version": 7 }, "cli": { "baseline": "2.1.0", "port-version": 0 }, "cli11": { - "baseline": "2.4.1", - "port-version": 0 + "baseline": "2.4.2", + "port-version": 1 }, "clickhouse-cpp": { "baseline": "2.5.1", @@ -1693,12 +1717,12 @@ "port-version": 2 }, "clipper2": { - "baseline": "1.3.0", - "port-version": 1 + "baseline": "1.4.0", + "port-version": 0 }, "clockutils": { "baseline": "1.1.1", - "port-version": 1 + "port-version": 2 }, "clrng": { "baseline": "2020-12-01", @@ -1725,7 +1749,7 @@ "port-version": 3 }, "cnats": { - "baseline": "3.8.0", + "baseline": "3.8.2", "port-version": 0 }, "cnl": { @@ -1741,15 +1765,15 @@ "port-version": 1 }, "coin": { - "baseline": "4.0.2", - "port-version": 2 + "baseline": "4.0.3", + "port-version": 0 }, "coin-or-buildtools": { "baseline": "2023-02-02", "port-version": 0 }, "coin-or-cbc": { - "baseline": "2023-02-01", + "baseline": "2024-06-04", "port-version": 0 }, "coin-or-cgl": { @@ -1765,19 +1789,19 @@ "port-version": 0 }, "coin-or-osi": { - "baseline": "2023-02-01", + "baseline": "2024-04-16", "port-version": 0 }, "coinutils": { - "baseline": "2023-02-02", - "port-version": 1 + "baseline": "2024-04-08", + "port-version": 0 }, "collada-dom": { "baseline": "2.5.0", "port-version": 11 }, "colmap": { - "baseline": "2023-10-01", + "baseline": "3.10", "port-version": 0 }, "color-console": { @@ -1793,7 +1817,7 @@ "port-version": 0 }, "commsdsl": { - "baseline": "4.0.0", + "baseline": "6.3.3", "port-version": 0 }, "compoundfilereader": { @@ -1802,14 +1826,18 @@ }, "concurrencpp": { "baseline": "0.1.7", - "port-version": 0 + "port-version": 1 }, "concurrentqueue": { "baseline": "1.0.4", "port-version": 0 }, "configcat": { - "baseline": "4.0.1", + "baseline": "4.0.3", + "port-version": 0 + }, + "conjure-enum": { + "baseline": "1.0.1", "port-version": 0 }, "console-bridge": { @@ -1861,7 +1889,7 @@ "port-version": 0 }, "cpp-httplib": { - "baseline": "0.15.3", + "baseline": "0.18.0", "port-version": 0 }, "cpp-ipc": { @@ -1877,7 +1905,7 @@ "port-version": 9 }, "cpp-peglib": { - "baseline": "1.8.6", + "baseline": "1.9.0", "port-version": 0 }, "cpp-redis": { @@ -1885,7 +1913,7 @@ "port-version": 5 }, "cpp-sort": { - "baseline": "1.15.0", + "baseline": "1.16.0", "port-version": 0 }, "cpp-taskflow": { @@ -1893,11 +1921,11 @@ "port-version": 2 }, "cpp-timsort": { - "baseline": "2.1.0", + "baseline": "3.0.0", "port-version": 0 }, "cppad": { - "baseline": "20240000.2", + "baseline": "20240000.6", "port-version": 0 }, "cppcms": { @@ -1921,8 +1949,8 @@ "port-version": 3 }, "cppgraphqlgen": { - "baseline": "4.5.5", - "port-version": 0 + "baseline": "4.5.7", + "port-version": 1 }, "cppitertools": { "baseline": "2.1", @@ -1940,9 +1968,13 @@ "baseline": "2.1.0", "port-version": 0 }, + "cpprealm": { + "baseline": "2.2.0", + "port-version": 0 + }, "cpprestsdk": { "baseline": "2.10.19", - "port-version": 0 + "port-version": 2 }, "cppslippi": { "baseline": "1.4.3.16", @@ -1953,7 +1985,7 @@ "port-version": 4 }, "cpptrace": { - "baseline": "0.5.4", + "baseline": "0.7.1", "port-version": 0 }, "cppunit": { @@ -1965,7 +1997,7 @@ "port-version": 3 }, "cppwinrt": { - "baseline": "2.0.240111.5", + "baseline": "2.0.240405.15", "port-version": 0 }, "cppxaml": { @@ -1998,7 +2030,7 @@ }, "crashpad": { "baseline": "2024-04-11", - "port-version": 0 + "port-version": 4 }, "crashrpt": { "baseline": "1.4.3", @@ -2010,7 +2042,7 @@ }, "crfsuite": { "baseline": "2020-08-27", - "port-version": 0 + "port-version": 1 }, "croncpp": { "baseline": "2023-03-30", @@ -2021,28 +2053,28 @@ "port-version": 3 }, "crow": { - "baseline": "1.1.0", + "baseline": "1.2.0", "port-version": 0 }, "cryptopp": { "baseline": "8.9.0", - "port-version": 0 + "port-version": 1 }, "cserialport": { - "baseline": "4.3.0", - "port-version": 1 + "baseline": "4.3.1", + "port-version": 0 }, "cspice": { "baseline": "67", "port-version": 3 }, "ctbench": { - "baseline": "1.3.3", + "baseline": "1.3.4", "port-version": 0 }, "ctbignum": { "baseline": "2019-08-02", - "port-version": 4 + "port-version": 5 }, "ctemplate": { "baseline": "2020-09-14", @@ -2057,7 +2089,7 @@ "port-version": 2 }, "ctre": { - "baseline": "3.8.1", + "baseline": "3.9.0", "port-version": 0 }, "ctstraffic": { @@ -2077,24 +2109,28 @@ "port-version": 13 }, "cuda-api-wrappers": { - "baseline": "0.6.9", + "baseline": "0.7.1", "port-version": 0 }, "cudnn": { "baseline": "7.6.5", - "port-version": 11 + "port-version": 14 }, "cunit": { "baseline": "2.1.3", "port-version": 8 }, "curl": { - "baseline": "8.7.1", - "port-version": 3 + "baseline": "8.10.1", + "port-version": 0 + }, + "curlcpp": { + "baseline": "3.1", + "port-version": 1 }, "curlpp": { "baseline": "2018-06-15", - "port-version": 9 + "port-version": 10 }, "cute-headers": { "baseline": "2019-09-20", @@ -2113,7 +2149,7 @@ "port-version": 0 }, "cxxgraph": { - "baseline": "2.0.0", + "baseline": "4.1.0", "port-version": 0 }, "cxxopts": { @@ -2128,6 +2164,10 @@ "baseline": "0.10.4", "port-version": 0 }, + "cyrus-sasl": { + "baseline": "2.1.28", + "port-version": 2 + }, "czmq": { "baseline": "4.2.1", "port-version": 4 @@ -2153,19 +2193,19 @@ "port-version": 3 }, "dataframe": { - "baseline": "3.1.0", + "baseline": "3.2.0", "port-version": 0 }, "date": { - "baseline": "3.0.1", - "port-version": 5 + "baseline": "2024-05-14", + "port-version": 0 }, "datraw": { "baseline": "1.0.9", "port-version": 0 }, "dav1d": { - "baseline": "1.4.0", + "baseline": "1.4.3", "port-version": 0 }, "daw-header-libraries": { @@ -2177,7 +2217,7 @@ "port-version": 0 }, "daw-utf-range": { - "baseline": "2.2.4", + "baseline": "2.2.5", "port-version": 0 }, "daxa": { @@ -2186,7 +2226,7 @@ }, "dbg-macro": { "baseline": "0.5.1", - "port-version": 0 + "port-version": 1 }, "dbghelp": { "baseline": "0", @@ -2202,15 +2242,15 @@ }, "dbus": { "baseline": "1.15.8", - "port-version": 4 + "port-version": 5 }, "dcmtk": { "baseline": "3.6.8", - "port-version": 5 + "port-version": 8 }, "debug-assert": { - "baseline": "1.3.3", - "port-version": 2 + "baseline": "1.3.4", + "port-version": 0 }, "decimal-for-cpp": { "baseline": "1.18", @@ -2232,16 +2272,20 @@ "baseline": "7.2.0", "port-version": 0 }, + "dingo": { + "baseline": "0.1.0", + "port-version": 0 + }, "directx-dxc": { - "baseline": "2024-03-29", + "baseline": "2024-07-31", "port-version": 0 }, "directx-headers": { - "baseline": "1.613.0", + "baseline": "1.614.1", "port-version": 0 }, "directx12-agility": { - "baseline": "1.613.0", + "baseline": "1.614.1", "port-version": 0 }, "directxmath": { @@ -2249,7 +2293,7 @@ "port-version": 1 }, "directxmesh": { - "baseline": "2024-02-21", + "baseline": "2024-09-04", "port-version": 0 }, "directxsdk": { @@ -2257,15 +2301,15 @@ "port-version": 8 }, "directxtex": { - "baseline": "2024-03-06", + "baseline": "2024-09-04", "port-version": 0 }, "directxtk": { - "baseline": "2024-02-21", + "baseline": "2024-09-04", "port-version": 0 }, "directxtk12": { - "baseline": "2024-02-21", + "baseline": "2024-09-04", "port-version": 0 }, "dirent": { @@ -2326,14 +2370,14 @@ }, "dp-thread-pool": { "baseline": "0.6.2", - "port-version": 0 + "port-version": 1 }, "dpdk": { - "baseline": "22.07", - "port-version": 1 + "baseline": "24.07", + "port-version": 0 }, "dpp": { - "baseline": "10.0.30", + "baseline": "10.0.31", "port-version": 0 }, "draco": { @@ -2349,15 +2393,15 @@ "port-version": 0 }, "drogon": { - "baseline": "1.9.4", + "baseline": "1.9.7", "port-version": 0 }, "dstorage": { - "baseline": "1.2.2", - "port-version": 0 + "baseline": "1.2.3", + "port-version": 1 }, "dtl": { - "baseline": "1.20", + "baseline": "1.21", "port-version": 0 }, "duckx": { @@ -2374,7 +2418,7 @@ }, "duktape": { "baseline": "2.7.0", - "port-version": 1 + "port-version": 2 }, "dumb": { "baseline": "2.0.3", @@ -2382,7 +2426,7 @@ }, "dv-processing": { "baseline": "1.7.9", - "port-version": 1 + "port-version": 2 }, "dx": { "baseline": "1.0.1", @@ -2426,7 +2470,7 @@ }, "easyhook": { "baseline": "2.7.7097.0", - "port-version": 7 + "port-version": 8 }, "easyloggingpp": { "baseline": "9.97.1", @@ -2441,27 +2485,23 @@ "port-version": 0 }, "ecal": { - "baseline": "5.12.0", + "baseline": "5.13.2", "port-version": 0 }, "ecm": { - "baseline": "5.98.0", + "baseline": "6.4.0", "port-version": 0 }, "ecos": { "baseline": "2.0.10", "port-version": 0 }, - "ecsutil": { - "baseline": "1.0.7.15", - "port-version": 5 - }, "ed25519": { "baseline": "2017-02-10", - "port-version": 0 + "port-version": 1 }, "edflib": { - "baseline": "1.25", + "baseline": "1.26", "port-version": 0 }, "edlib": { @@ -2477,7 +2517,7 @@ "port-version": 0 }, "efsw": { - "baseline": "1.3.1", + "baseline": "1.4.0", "port-version": 0 }, "egl": { @@ -2501,12 +2541,12 @@ "port-version": 0 }, "elfutils": { - "baseline": "0.186", - "port-version": 4 + "baseline": "0.191", + "port-version": 0 }, "embree3": { "baseline": "3.13.5", - "port-version": 3 + "port-version": 4 }, "enet": { "baseline": "1.3.17", @@ -2514,7 +2554,7 @@ }, "enkits": { "baseline": "1.11", - "port-version": 2 + "port-version": 3 }, "ensmallen": { "baseline": "2.19.1", @@ -2522,7 +2562,7 @@ }, "entityx": { "baseline": "1.3.0", - "port-version": 5 + "port-version": 6 }, "entt": { "baseline": "3.13.2", @@ -2561,15 +2601,15 @@ "port-version": 8 }, "exiv2": { - "baseline": "0.28.1", + "baseline": "0.28.3", "port-version": 1 }, "expat": { - "baseline": "2.6.2", + "baseline": "2.6.3", "port-version": 0 }, "expected-lite": { - "baseline": "0.6.3", + "baseline": "0.8.0", "port-version": 0 }, "exprtk": { @@ -2594,11 +2634,11 @@ }, "faiss": { "baseline": "1.7.4", - "port-version": 0 + "port-version": 1 }, "fakeit": { "baseline": "2.4.0", - "port-version": 2 + "port-version": 3 }, "fameta-counter": { "baseline": "2021-02-13", @@ -2616,12 +2656,16 @@ "baseline": "2021-01-03", "port-version": 2 }, + "fast-double-parser": { + "baseline": "0.8.0", + "port-version": 0 + }, "fast-float": { - "baseline": "6.1.1", + "baseline": "6.1.6", "port-version": 0 }, "fastcdr": { - "baseline": "1.1.0", + "baseline": "2.2.1", "port-version": 0 }, "fastcgi": { @@ -2633,11 +2677,11 @@ "port-version": 4 }, "fastgltf": { - "baseline": "0.7.1", + "baseline": "0.7.2", "port-version": 0 }, "fastio": { - "baseline": "2023-11-06", + "baseline": "2024-07-05", "port-version": 0 }, "fastlz": { @@ -2649,11 +2693,11 @@ "port-version": 1 }, "fastrtps": { - "baseline": "2.7.0", - "port-version": 5 + "baseline": "2.14.0", + "port-version": 0 }, "faudio": { - "baseline": "24.03", + "baseline": "24.06", "port-version": 0 }, "fawdlstty-libfv": { @@ -2662,10 +2706,10 @@ }, "fbgemm": { "baseline": "0.4.1", - "port-version": 0 + "port-version": 1 }, "fbthrift": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "fcl": { @@ -2674,15 +2718,19 @@ }, "fdk-aac": { "baseline": "2.0.2", - "port-version": 3 + "port-version": 4 }, "fdlibm": { "baseline": "5.3", "port-version": 7 }, + "fenster": { + "baseline": "2024-08-19", + "port-version": 0 + }, "ffmpeg": { - "baseline": "6.1.1", - "port-version": 3 + "baseline": "7.0.2", + "port-version": 4 }, "ffnvcodec": { "baseline": "12.1.14.0", @@ -2690,7 +2738,7 @@ }, "fftw3": { "baseline": "3.3.10", - "port-version": 8 + "port-version": 9 }, "fftwpp": { "baseline": "2019-12-19", @@ -2709,7 +2757,7 @@ "port-version": 0 }, "fizz": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "flagpp": { @@ -2749,11 +2797,11 @@ "port-version": 0 }, "flatbush": { - "baseline": "1.2.0", + "baseline": "1.2.1", "port-version": 0 }, "flecs": { - "baseline": "3.2.11", + "baseline": "4.0.1", "port-version": 0 }, "flint": { @@ -2762,14 +2810,14 @@ }, "fltk": { "baseline": "1.3.9", - "port-version": 0 + "port-version": 1 }, "fluidlite": { "baseline": "2023-04-18", "port-version": 0 }, "fluidsynth": { - "baseline": "2.3.5", + "baseline": "2.3.6", "port-version": 0 }, "flux": { @@ -2789,11 +2837,11 @@ "port-version": 2 }, "fmt": { - "baseline": "10.2.1", - "port-version": 2 + "baseline": "11.0.2", + "port-version": 0 }, "folly": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "font-chef": { @@ -2805,8 +2853,8 @@ "port-version": 0 }, "fontconfig": { - "baseline": "2.14.2", - "port-version": 1 + "baseline": "2.15.0", + "port-version": 0 }, "foonathan-lexy": { "baseline": "2022.12.1", @@ -2814,7 +2862,7 @@ }, "foonathan-memory": { "baseline": "0.7.3", - "port-version": 1 + "port-version": 2 }, "forge": { "baseline": "1.0.8", @@ -2834,11 +2882,11 @@ }, "freeglut": { "baseline": "3.4.0", - "port-version": 1 + "port-version": 3 }, "freeimage": { "baseline": "3.18.0", - "port-version": 26 + "port-version": 27 }, "freeopcua": { "baseline": "20190125", @@ -2846,15 +2894,15 @@ }, "freerdp": { "baseline": "3.4.0", - "port-version": 1 + "port-version": 3 }, "freetds": { "baseline": "1.3.10", "port-version": 2 }, "freetype": { - "baseline": "2.13.2", - "port-version": 1 + "baseline": "2.13.3", + "port-version": 0 }, "freetype-gl": { "baseline": "2022-01-17", @@ -2865,11 +2913,11 @@ "port-version": 0 }, "fribidi": { - "baseline": "1.0.13", + "baseline": "1.0.15", "port-version": 0 }, "frozen": { - "baseline": "1.1.1", + "baseline": "1.2.0", "port-version": 0 }, "frugally-deep": { @@ -2881,8 +2929,8 @@ "port-version": 0 }, "ftgl": { - "baseline": "2022-05-18", - "port-version": 1 + "baseline": "2.4.0", + "port-version": 5 }, "ftxui": { "baseline": "5.0.0", @@ -2893,7 +2941,7 @@ "port-version": 0 }, "functionalplus": { - "baseline": "0.2.24", + "baseline": "0.2.25", "port-version": 0 }, "functions-framework-cpp": { @@ -2957,7 +3005,7 @@ "port-version": 0 }, "gdal": { - "baseline": "3.8.5", + "baseline": "3.9.2", "port-version": 0 }, "gdcm": { @@ -2969,8 +3017,8 @@ "port-version": 1 }, "gdk-pixbuf": { - "baseline": "2.42.10", - "port-version": 6 + "baseline": "2.42.12", + "port-version": 1 }, "gemmlowp": { "baseline": "2021-09-28", @@ -2982,15 +3030,15 @@ }, "geogram": { "baseline": "1.8.3", - "port-version": 1 + "port-version": 3 }, "geographiclib": { - "baseline": "2.3", - "port-version": 1 + "baseline": "2.4", + "port-version": 0 }, "geos": { - "baseline": "3.11.3", - "port-version": 1 + "baseline": "3.12.2", + "port-version": 0 }, "geotrans": { "baseline": "3.9", @@ -3010,11 +3058,11 @@ }, "gettext": { "baseline": "0.22.5", - "port-version": 0 + "port-version": 1 }, "gettext-libintl": { "baseline": "0.22.5", - "port-version": 0 + "port-version": 2 }, "gettimeofday": { "baseline": "2017-10-14", @@ -3037,7 +3085,7 @@ "port-version": 0 }, "ginkgo": { - "baseline": "1.7.0", + "baseline": "1.8.0", "port-version": 0 }, "gklib": { @@ -3057,7 +3105,7 @@ "port-version": 0 }, "glaze": { - "baseline": "2.6.1", + "baseline": "3.4.0", "port-version": 0 }, "glbinding": { @@ -3070,7 +3118,7 @@ }, "glfw3": { "baseline": "3.4", - "port-version": 0 + "port-version": 1 }, "gli": { "baseline": "2021-07-06", @@ -3078,7 +3126,7 @@ }, "glib": { "baseline": "2.78.4", - "port-version": 1 + "port-version": 3 }, "glib-networking": { "baseline": "2.78.0", @@ -3090,15 +3138,15 @@ }, "glm": { "baseline": "1.0.1", - "port-version": 2 + "port-version": 3 }, "globjects": { "baseline": "1.1.0", "port-version": 6 }, "glog": { - "baseline": "0.7.0", - "port-version": 1 + "baseline": "0.7.1", + "port-version": 0 }, "gloo": { "baseline": "20201203", @@ -3109,7 +3157,7 @@ "port-version": 3 }, "glslang": { - "baseline": "14.2.0", + "baseline": "14.3.0", "port-version": 0 }, "glui": { @@ -3121,7 +3169,7 @@ "port-version": 6 }, "gmmlib": { - "baseline": "22.3.17", + "baseline": "22.3.20", "port-version": 0 }, "gmp": { @@ -3130,14 +3178,18 @@ }, "gmsh": { "baseline": "4.12.2", - "port-version": 0 + "port-version": 1 }, "gobject-introspection": { "baseline": "1.72.0", "port-version": 8 }, + "godot-cpp": { + "baseline": "4.2.1", + "port-version": 0 + }, "google-cloud-cpp": { - "baseline": "2.24.0", + "baseline": "2.29.0", "port-version": 0 }, "google-cloud-cpp-common": { @@ -3184,33 +3236,33 @@ "baseline": "1.3.41", "port-version": 1 }, - "graphite2": { - "baseline": "1.3.14", - "port-version": 4 - }, - "graphqlparser": { - "baseline": "0.7.0", + "graphite2": { + "baseline": "1.3.14", "port-version": 4 }, "graphviz": { "baseline": "10.0.1", - "port-version": 1 + "port-version": 2 }, "greatest": { "baseline": "1.5.0", "port-version": 0 }, "grpc": { - "baseline": "1.51.1", - "port-version": 3 + "baseline": "1.60.0", + "port-version": 1 }, "grppi": { "baseline": "0.4.0", "port-version": 2 }, + "gsasl": { + "baseline": "2.2.1", + "port-version": 0 + }, "gsl": { - "baseline": "2.7.1", - "port-version": 3 + "baseline": "2.8", + "port-version": 0 }, "gsl-lite": { "baseline": "0.41.0", @@ -3225,24 +3277,24 @@ "port-version": 2 }, "gstreamer": { - "baseline": "1.22.5", - "port-version": 8 + "baseline": "1.24.7", + "port-version": 0 }, "gtest": { - "baseline": "1.14.0", - "port-version": 1 + "baseline": "1.15.2", + "port-version": 0 }, "gtk": { - "baseline": "4.10.5", - "port-version": 2 + "baseline": "4.14.0", + "port-version": 1 }, "gtk3": { "baseline": "3.24.38", "port-version": 1 }, "gtkmm": { - "baseline": "4.10.0", - "port-version": 1 + "baseline": "4.14.0", + "port-version": 0 }, "gtl": { "baseline": "1.1.8", @@ -3253,8 +3305,8 @@ "port-version": 9 }, "gtsam": { - "baseline": "4.2a9", - "port-version": 1 + "baseline": "4.2.0", + "port-version": 0 }, "guetzli": { "baseline": "2020-09-14", @@ -3262,7 +3314,7 @@ }, "guile": { "baseline": "3.0.9", - "port-version": 0 + "port-version": 1 }, "guilite": { "baseline": "2022-05-05", @@ -3282,7 +3334,7 @@ }, "gz-common5": { "baseline": "5.4.1", - "port-version": 1 + "port-version": 2 }, "gz-fuel-tools8": { "baseline": "8.1.0", @@ -3321,7 +3373,7 @@ "port-version": 1 }, "gz-transport12": { - "baseline": "12.2.0", + "baseline": "12.2.1", "port-version": 0 }, "gz-utils2": { @@ -3340,9 +3392,13 @@ "baseline": "2022-05-24", "port-version": 0 }, + "half": { + "baseline": "2.2.0", + "port-version": 0 + }, "halide": { "baseline": "17.0.1", - "port-version": 0 + "port-version": 1 }, "happly": { "baseline": "2021-03-19", @@ -3353,27 +3409,31 @@ "port-version": 0 }, "harfbuzz": { - "baseline": "8.4.0", - "port-version": 1 + "baseline": "9.0.0", + "port-version": 0 }, "hash-library": { "baseline": "8", - "port-version": 2 + "port-version": 3 }, "hashids": { - "baseline": "1.2.1", + "baseline": "1.2.2", "port-version": 0 }, "hayai": { "baseline": "2019-08-10", - "port-version": 3 + "port-version": 4 }, "hazelcast-cpp-client": { "baseline": "5.3.0", "port-version": 0 }, "hdf5": { - "baseline": "1.14.2", + "baseline": "1.14.4.3", + "port-version": 2 + }, + "hdr-histogram": { + "baseline": "0.11.8", "port-version": 0 }, "healpix": { @@ -3385,15 +3445,15 @@ "port-version": 0 }, "hello-imgui": { - "baseline": "1.4.2", - "port-version": 1 + "baseline": "1.5.2", + "port-version": 0 }, "hexl": { "baseline": "1.2.5", "port-version": 0 }, "hffix": { - "baseline": "1.3.0", + "baseline": "1.4.1", "port-version": 0 }, "hfsm2": { @@ -3402,18 +3462,18 @@ }, "hidapi": { "baseline": "0.14.0", - "port-version": 0 + "port-version": 1 }, "highfive": { - "baseline": "2.9.0", + "baseline": "2.10.0", "port-version": 0 }, "highs": { - "baseline": "1.6.0", - "port-version": 1 + "baseline": "1.7.2", + "port-version": 0 }, "highway": { - "baseline": "1.1.0", + "baseline": "1.2.0", "port-version": 0 }, "hikogui": { @@ -3428,6 +3488,10 @@ "baseline": "2.4.1", "port-version": 0 }, + "hlslpp": { + "baseline": "3.5", + "port-version": 0 + }, "hnswlib": { "baseline": "0.8.0", "port-version": 0 @@ -3437,9 +3501,17 @@ "port-version": 0 }, "hpx": { - "baseline": "1.9.1", + "baseline": "1.10.0", "port-version": 1 }, + "htscodecs": { + "baseline": "1.6.0", + "port-version": 0 + }, + "htslib": { + "baseline": "1.20", + "port-version": 0 + }, "http-parser": { "baseline": "2.9.4", "port-version": 3 @@ -3454,14 +3526,14 @@ }, "hwloc": { "baseline": "2.10.0", - "port-version": 0 + "port-version": 1 }, "hyperscan": { "baseline": "5.4.2", "port-version": 0 }, "hypodermic": { - "baseline": "2.5.3", + "baseline": "2023-03-03", "port-version": 0 }, "hypre": { @@ -3474,7 +3546,7 @@ }, "icu": { "baseline": "74.2", - "port-version": 1 + "port-version": 4 }, "ideviceinstaller": { "baseline": "2023-07-21", @@ -3485,7 +3557,7 @@ "port-version": 0 }, "idyntree": { - "baseline": "12.1.0", + "baseline": "12.4.0", "port-version": 0 }, "if97": { @@ -3534,15 +3606,15 @@ }, "ignition-msgs1": { "baseline": "1.0.0", - "port-version": 6 + "port-version": 7 }, "ignition-msgs5": { "baseline": "5.3.0", - "port-version": 6 + "port-version": 7 }, "ignition-msgs6": { "baseline": "6.0.0", - "port-version": 5 + "port-version": 6 }, "ignition-plugin1": { "baseline": "1.4.0", @@ -3554,22 +3626,22 @@ }, "ignition-transport4": { "baseline": "4.0.0", - "port-version": 6 + "port-version": 7 }, "ignition-transport8": { "baseline": "8.1.0", - "port-version": 4 + "port-version": 5 }, "ignition-transport9": { "baseline": "9.0.0", - "port-version": 4 + "port-version": 5 }, "ignition-utils1": { "baseline": "1.5.1", "port-version": 0 }, "igraph": { - "baseline": "0.10.12", + "baseline": "0.10.13", "port-version": 0 }, "iir1": { @@ -3578,26 +3650,26 @@ }, "ijg-libjpeg": { "baseline": "9e", - "port-version": 1 - }, - "ilmbase": { - "baseline": "3", - "port-version": 0 + "port-version": 2 }, "im3d": { "baseline": "2022-10-11", "port-version": 0 }, "imageinfo": { - "baseline": "2024-02-21", + "baseline": "2024-08-05", "port-version": 0 }, "imath": { "baseline": "3.1.11", "port-version": 0 }, + "imcce-openfa": { + "baseline": "20231011.0.3", + "port-version": 0 + }, "imgui": { - "baseline": "1.90.2", + "baseline": "1.91.0", "port-version": 0 }, "imgui-node-editor": { @@ -3609,7 +3681,7 @@ "port-version": 0 }, "imguizmo": { - "baseline": "1.83", + "baseline": "2024-05-29", "port-version": 1 }, "immer": { @@ -3658,7 +3730,7 @@ }, "intel-mkl": { "baseline": "2023.0.0", - "port-version": 3 + "port-version": 4 }, "intelrdfpmathlib": { "baseline": "20U2", @@ -3693,12 +3765,12 @@ "port-version": 0 }, "itk": { - "baseline": "5.3rc02", - "port-version": 1 + "baseline": "5.4.0", + "port-version": 0 }, "itpp": { "baseline": "4.3.1", - "port-version": 10 + "port-version": 11 }, "itsy-bitsy": { "baseline": "2022-08-02", @@ -3740,6 +3812,10 @@ "baseline": "2023-12-27", "port-version": 0 }, + "jigson": { + "baseline": "0.1.3", + "port-version": 0 + }, "jinja2cpplight": { "baseline": "2018-05-08", "port-version": 3 @@ -3749,7 +3825,7 @@ "port-version": 1 }, "joltphysics": { - "baseline": "5.0.0", + "baseline": "5.1.0", "port-version": 1 }, "josuttis-jthread": { @@ -3765,7 +3841,7 @@ "port-version": 0 }, "json-dto": { - "baseline": "0.3.3", + "baseline": "0.3.4", "port-version": 0 }, "json-rpc-cxx": { @@ -3789,15 +3865,15 @@ "port-version": 6 }, "jsoncons": { - "baseline": "0.175.0", + "baseline": "0.177.0", "port-version": 0 }, "jsoncpp": { "baseline": "1.9.5", - "port-version": 4 + "port-version": 5 }, "jsonifier": { - "baseline": "0.9.95", + "baseline": "0.9.96", "port-version": 0 }, "jsonnet": { @@ -3814,7 +3890,7 @@ }, "jxrlib": { "baseline": "2019.10.9", - "port-version": 6 + "port-version": 7 }, "kaitai-struct-cpp-stl-runtime": { "baseline": "0.10.1", @@ -3837,7 +3913,7 @@ "port-version": 0 }, "kddockwidgets": { - "baseline": "2.0.0", + "baseline": "2.1.0", "port-version": 0 }, "kdsoap": { @@ -3850,14 +3926,14 @@ }, "keccak-tiny": { "baseline": "2014-09-08", - "port-version": 0 + "port-version": 2 }, "kenlm": { "baseline": "20230531", "port-version": 1 }, "kerbal": { - "baseline": "2024.4.1", + "baseline": "2024.8.1", "port-version": 0 }, "keystone": { @@ -3954,7 +4030,7 @@ }, "kf5kio": { "baseline": "5.98.0", - "port-version": 0 + "port-version": 1 }, "kf5newstuff": { "baseline": "5.98.0", @@ -3994,7 +4070,7 @@ }, "kf5texteditor": { "baseline": "5.98.0", - "port-version": 0 + "port-version": 1 }, "kf5textwidgets": { "baseline": "5.98.0", @@ -4049,12 +4125,12 @@ "port-version": 0 }, "krb5": { - "baseline": "1.21.2", - "port-version": 0 + "baseline": "1.21.3", + "port-version": 1 }, "ktx": { - "baseline": "4.3.1", - "port-version": 1 + "baseline": "4.3.2", + "port-version": 0 }, "kubazip": { "baseline": "0.2.6", @@ -4082,15 +4158,15 @@ }, "lapack": { "baseline": "2023-06-10", - "port-version": 0 + "port-version": 2 }, "lapack-reference": { "baseline": "3.11.0", "port-version": 6 }, "lastools": { - "baseline": "2.0.2+20230206", - "port-version": 1 + "baseline": "2.0.3", + "port-version": 0 }, "laszip": { "baseline": "3.4.4", @@ -4130,15 +4206,19 @@ }, "leptonica": { "baseline": "1.84.1", - "port-version": 0 + "port-version": 1 }, "lerc": { "baseline": "4.0.4", "port-version": 0 }, "lest": { - "baseline": "1.35.1", - "port-version": 3 + "baseline": "1.35.2", + "port-version": 0 + }, + "level-zero": { + "baseline": "1.17.28", + "port-version": 0 }, "leveldb": { "baseline": "1.23", @@ -4152,6 +4232,14 @@ "baseline": "2.3.0", "port-version": 0 }, + "lfreist-hwinfo": { + "baseline": "2024-09-01", + "port-version": 0 + }, + "lib3mf": { + "baseline": "2.3.2", + "port-version": 0 + }, "libaaplus": { "baseline": "2.36", "port-version": 1 @@ -4172,6 +4260,10 @@ "baseline": "5.0", "port-version": 9 }, + "libaio": { + "baseline": "0.3.113", + "port-version": 0 + }, "libalkimia": { "baseline": "8.1.72", "port-version": 0 @@ -4181,15 +4273,15 @@ "port-version": 5 }, "libarchive": { - "baseline": "3.7.2", + "baseline": "3.7.5", "port-version": 0 }, "libass": { - "baseline": "0.17.1", + "baseline": "0.17.3", "port-version": 0 }, "libassert": { - "baseline": "2.0.2", + "baseline": "2.1.1", "port-version": 0 }, "libassuan": { @@ -4202,7 +4294,7 @@ }, "libavif": { "baseline": "1.0.4", - "port-version": 0 + "port-version": 2 }, "libb2": { "baseline": "0.98.1", @@ -4217,7 +4309,7 @@ "port-version": 4 }, "libbson": { - "baseline": "1.27.1", + "baseline": "1.28.0", "port-version": 0 }, "libcaer": { @@ -4229,8 +4321,8 @@ "port-version": 4 }, "libcap": { - "baseline": "2.69", - "port-version": 5 + "baseline": "2.70", + "port-version": 0 }, "libcbor": { "baseline": "0.11.0", @@ -4241,23 +4333,27 @@ "port-version": 4 }, "libcerf": { - "baseline": "1.13", - "port-version": 4 + "baseline": "2.4", + "port-version": 0 + }, + "libcgroup": { + "baseline": "3.1.0", + "port-version": 0 }, "libconfig": { "baseline": "1.7.3", "port-version": 5 }, "libconfuse": { - "baseline": "2019-07-14", - "port-version": 4 + "baseline": "3.3", + "port-version": 0 }, "libcopp": { "baseline": "2.2.0", - "port-version": 0 + "port-version": 1 }, "libcoro": { - "baseline": "0.11.1", + "baseline": "0.12.1", "port-version": 0 }, "libcorrect": { @@ -4274,7 +4370,7 @@ }, "libcroco": { "baseline": "0.6.13", - "port-version": 6 + "port-version": 7 }, "libcsv": { "baseline": "3.0.3", @@ -4289,8 +4385,8 @@ "port-version": 0 }, "libdatachannel": { - "baseline": "0.20.3", - "port-version": 0 + "baseline": "0.21.2", + "port-version": 1 }, "libdatrie": { "baseline": "0.2.13", @@ -4305,7 +4401,7 @@ "port-version": 0 }, "libdeflate": { - "baseline": "1.20", + "baseline": "1.21", "port-version": 0 }, "libdisasm": { @@ -4313,11 +4409,11 @@ "port-version": 11 }, "libdivide": { - "baseline": "5.0", - "port-version": 1 + "baseline": "5.1", + "port-version": 0 }, "libdjinterop": { - "baseline": "0.20.3", + "baseline": "0.21.0", "port-version": 0 }, "libdmx": { @@ -4328,9 +4424,13 @@ "baseline": "0.6.0", "port-version": 3 }, + "libdvdcss": { + "baseline": "1.4.3", + "port-version": 0 + }, "libdwarf": { - "baseline": "0.9.1", - "port-version": 1 + "baseline": "0.11.0", + "port-version": 0 }, "libe57": { "baseline": "1.1.332", @@ -4345,7 +4445,7 @@ "port-version": 2 }, "libenvpp": { - "baseline": "1.4.0", + "baseline": "1.4.1", "port-version": 0 }, "libepoxy": { @@ -4358,18 +4458,18 @@ }, "libev": { "baseline": "4.33", - "port-version": 2 + "port-version": 3 }, "libevent": { "baseline": "2.1.12+20230128", - "port-version": 0 + "port-version": 1 }, "libeventheader-decode": { - "baseline": "1.3.3", + "baseline": "1.4.0", "port-version": 0 }, "libeventheader-tracepoint": { - "baseline": "1.3.3", + "baseline": "1.4.0", "port-version": 0 }, "libevhtp": { @@ -4401,7 +4501,7 @@ "port-version": 0 }, "libfork": { - "baseline": "3.7.1", + "baseline": "3.8.0", "port-version": 0 }, "libfort": { @@ -4422,7 +4522,7 @@ }, "libftdi1": { "baseline": "1.5", - "port-version": 4 + "port-version": 5 }, "libfuse": { "baseline": "3.16.2", @@ -4437,8 +4537,8 @@ "port-version": 3 }, "libgeotiff": { - "baseline": "1.7.1", - "port-version": 3 + "baseline": "1.7.3", + "port-version": 1 }, "libgig": { "baseline": "4.4.1", @@ -4453,7 +4553,7 @@ "port-version": 0 }, "libgnutls": { - "baseline": "3.8.5", + "baseline": "3.8.7.1", "port-version": 0 }, "libgo": { @@ -4465,7 +4565,7 @@ "port-version": 0 }, "libgpiod": { - "baseline": "2.1", + "baseline": "2.1.2", "port-version": 0 }, "libgpod": { @@ -4486,7 +4586,7 @@ }, "libgxps": { "baseline": "0.3.2", - "port-version": 3 + "port-version": 4 }, "libharu": { "baseline": "2.4.4", @@ -4497,8 +4597,8 @@ "port-version": 6 }, "libheif": { - "baseline": "1.17.6", - "port-version": 1 + "baseline": "1.18.2", + "port-version": 0 }, "libhsplasma": { "baseline": "2024-03-07", @@ -4517,12 +4617,12 @@ "port-version": 0 }, "libice": { - "baseline": "1.0.10", - "port-version": 1 + "baseline": "1.1.1", + "port-version": 0 }, "libiconv": { "baseline": "1.17", - "port-version": 3 + "port-version": 4 }, "libics": { "baseline": "1.6.6", @@ -4537,12 +4637,12 @@ "port-version": 1 }, "libidn2": { - "baseline": "2.3.4", - "port-version": 3 + "baseline": "2.3.7", + "port-version": 1 }, "libigl": { "baseline": "2.5.0", - "port-version": 0 + "port-version": 2 }, "libilbc": { "baseline": "3.0.4", @@ -4561,16 +4661,16 @@ "port-version": 2 }, "libjpeg-turbo": { - "baseline": "3.0.2", + "baseline": "3.0.4", "port-version": 0 }, "libjuice": { - "baseline": "1.3.4", - "port-version": 1 + "baseline": "1.5.2", + "port-version": 0 }, "libjxl": { - "baseline": "0.10.2", - "port-version": 2 + "baseline": "0.11.0", + "port-version": 0 }, "libkeyfinder": { "baseline": "2.2.8", @@ -4582,7 +4682,7 @@ }, "liblas": { "baseline": "1.8.1", - "port-version": 14 + "port-version": 15 }, "liblbfgs": { "baseline": "1.10", @@ -4614,14 +4714,14 @@ }, "liblsquic": { "baseline": "3.3.2", - "port-version": 0 + "port-version": 1 }, "liblzf": { "baseline": "3.6", "port-version": 1 }, "liblzma": { - "baseline": "5.4.4", + "baseline": "5.6.2", "port-version": 0 }, "libmad": { @@ -4630,18 +4730,18 @@ }, "libmagic": { "baseline": "5.45", - "port-version": 2 + "port-version": 3 }, "libmariadb": { "baseline": "3.3.1", - "port-version": 3 + "port-version": 4 }, "libmaxminddb": { "baseline": "1.9.1", "port-version": 0 }, "libmediainfo": { - "baseline": "24.3", + "baseline": "24.6", "port-version": 0 }, "libmesh": { @@ -4657,7 +4757,7 @@ "port-version": 1 }, "libmidi2": { - "baseline": "0.10", + "baseline": "0.11", "port-version": 0 }, "libmikmod": { @@ -4674,7 +4774,7 @@ }, "libmodplug": { "baseline": "0.8.9.0", - "port-version": 11 + "port-version": 13 }, "libmorton": { "baseline": "0.2.12", @@ -4701,8 +4801,8 @@ "port-version": 0 }, "libmysql": { - "baseline": "8.0.34", - "port-version": 1 + "baseline": "8.0.39", + "port-version": 0 }, "libnice": { "baseline": "0.1.21", @@ -4713,7 +4813,7 @@ "port-version": 4 }, "libnick": { - "baseline": "2024.3.1", + "baseline": "2024.9.2", "port-version": 0 }, "libnoise": { @@ -4725,12 +4825,12 @@ "port-version": 0 }, "libobfuscate": { - "baseline": "2023-03-23", + "baseline": "2024-02-11", "port-version": 0 }, "libodb": { "baseline": "2.4.0", - "port-version": 10 + "port-version": 12 }, "libodb-boost": { "baseline": "2.4.0", @@ -4742,11 +4842,11 @@ }, "libodb-pgsql": { "baseline": "2.4.0", - "port-version": 7 + "port-version": 8 }, "libodb-sqlite": { "baseline": "2.4.0", - "port-version": 11 + "port-version": 12 }, "libofx": { "baseline": "0.10.9", @@ -4758,7 +4858,7 @@ }, "libopenmpt": { "baseline": "0.7.4", - "port-version": 0 + "port-version": 1 }, "libopensp": { "baseline": "1.5.2", @@ -4772,9 +4872,9 @@ "baseline": "0.2.1", "port-version": 3 }, - "liborigin": { - "baseline": "3.0.2", - "port-version": 1 + "liborigin": { + "baseline": "3.0.3", + "port-version": 0 }, "libosdp": { "baseline": "3.0.5", @@ -4782,7 +4882,7 @@ }, "libosip2": { "baseline": "5.3.1", - "port-version": 0 + "port-version": 1 }, "libosmium": { "baseline": "2.20.0", @@ -4790,7 +4890,7 @@ }, "libosmscout": { "baseline": "1.1.1", - "port-version": 4 + "port-version": 5 }, "libp7-baical": { "baseline": "replaced", @@ -4798,7 +4898,7 @@ }, "libp7client": { "baseline": "5.6", - "port-version": 4 + "port-version": 5 }, "libpcap": { "baseline": "1.10.4", @@ -4809,7 +4909,7 @@ "port-version": 2 }, "libphonenumber": { - "baseline": "8.13.31", + "baseline": "8.13.45", "port-version": 0 }, "libplist": { @@ -4822,22 +4922,22 @@ }, "libpng": { "baseline": "1.6.43", - "port-version": 1 + "port-version": 3 }, "libpopt": { "baseline": "1.16", - "port-version": 16 + "port-version": 17 }, "libpq": { - "baseline": "16.2", - "port-version": 1 + "baseline": "16.4", + "port-version": 0 }, "libpqxx": { - "baseline": "7.9.0", + "baseline": "7.9.2", "port-version": 0 }, "libprotobuf-mutator": { - "baseline": "1.1", + "baseline": "1.3", "port-version": 0 }, "libproxy": { @@ -4846,7 +4946,7 @@ }, "libpsl": { "baseline": "0.21.5", - "port-version": 0 + "port-version": 1 }, "libqcow": { "baseline": "20221124", @@ -4878,23 +4978,23 @@ }, "librdkafka": { "baseline": "2.3.0", - "port-version": 0 + "port-version": 5 }, "libredwg": { "baseline": "0.13.3", - "port-version": 0 + "port-version": 1 }, "libremidi": { - "baseline": "4.3.0", + "baseline": "4.5.0", "port-version": 0 }, "libressl": { - "baseline": "3.8.2", - "port-version": 0 + "baseline": "3.9.2", + "port-version": 1 }, "librsvg": { "baseline": "2.40.20", - "port-version": 10 + "port-version": 11 }, "librsync": { "baseline": "2.3.4", @@ -4932,16 +5032,20 @@ "baseline": "1.3.2", "port-version": 1 }, + "libsersi": { + "baseline": "0.1.0", + "port-version": 0 + }, "libsigcpp": { "baseline": "3.6.0", - "port-version": 0 + "port-version": 1 }, "libsigcpp-3": { "baseline": "3.0.3", "port-version": 1 }, "libslirp": { - "baseline": "4.7.0", + "baseline": "4.8.0", "port-version": 0 }, "libsm": { @@ -4965,8 +5069,8 @@ "port-version": 2 }, "libsodium": { - "baseline": "1.0.19", - "port-version": 2 + "baseline": "1.0.20", + "port-version": 3 }, "libsonic": { "baseline": "0.2.0", @@ -4978,7 +5082,7 @@ }, "libsoup": { "baseline": "3.4.4", - "port-version": 0 + "port-version": 1 }, "libspatialindex": { "baseline": "1.9.3", @@ -4986,7 +5090,7 @@ }, "libspatialite": { "baseline": "5.1.0", - "port-version": 1 + "port-version": 2 }, "libspnav": { "baseline": "0.2.3", @@ -4998,27 +5102,27 @@ }, "libsquish": { "baseline": "1.15", - "port-version": 13 + "port-version": 14 }, "libsrt": { "baseline": "1.5.3", - "port-version": 0 + "port-version": 2 }, "libsrtp": { "baseline": "2.5.0", "port-version": 1 }, "libssh": { - "baseline": "0.10.5", - "port-version": 1 + "baseline": "0.10.6", + "port-version": 0 }, "libssh2": { "baseline": "1.11.0", - "port-version": 1 + "port-version": 2 }, "libstemmer": { - "baseline": "2017-9", - "port-version": 8 + "baseline": "2021.2.2.0", + "port-version": 0 }, "libstk": { "baseline": "4.6.1", @@ -5026,11 +5130,11 @@ }, "libsvm": { "baseline": "3.32", - "port-version": 0 + "port-version": 1 }, "libsystemd": { - "baseline": "255", - "port-version": 2 + "baseline": "256.4", + "port-version": 0 }, "libtar": { "baseline": "1.2.20", @@ -5066,22 +5170,22 @@ }, "libtorch": { "baseline": "2.1.2", - "port-version": 2 + "port-version": 6 }, "libtorrent": { "baseline": "2.0.10", "port-version": 0 }, "libtracepoint": { - "baseline": "1.3.3", + "baseline": "1.4.0", "port-version": 0 }, "libtracepoint-control": { - "baseline": "1.3.3", + "baseline": "1.4.0", "port-version": 0 }, "libtracepoint-decode": { - "baseline": "1.3.3", + "baseline": "1.4.0", "port-version": 0 }, "libu2f-server": { @@ -5090,11 +5194,11 @@ }, "libudis86": { "baseline": "2018-01-28", - "port-version": 3 + "port-version": 4 }, "libudns": { "baseline": "0.4", - "port-version": 5 + "port-version": 6 }, "libui": { "baseline": "2018-11-03", @@ -5117,12 +5221,12 @@ "port-version": 0 }, "liburing": { - "baseline": "2.6", - "port-version": 0 + "baseline": "2.7", + "port-version": 1 }, "libusb": { "baseline": "1.0.27", - "port-version": 1 + "port-version": 2 }, "libusb-win32": { "baseline": "1.2.6.0", @@ -5132,17 +5236,21 @@ "baseline": "2023-06-21", "port-version": 1 }, + "libusbp": { + "baseline": "1.3.1", + "port-version": 0 + }, "libuuid": { "baseline": "1.0.3", "port-version": 14 }, "libuv": { - "baseline": "1.46.0", + "baseline": "1.48.0", "port-version": 1 }, "libuvc": { "baseline": "0.0.7", - "port-version": 0 + "port-version": 1 }, "libvault": { "baseline": "0.56.0", @@ -5154,11 +5262,11 @@ }, "libvmdk": { "baseline": "20221124", - "port-version": 0 + "port-version": 1 }, "libvorbis": { "baseline": "1.3.7", - "port-version": 2 + "port-version": 3 }, "libvpx": { "baseline": "1.13.1", @@ -5169,16 +5277,16 @@ "port-version": 6 }, "libwebm": { - "baseline": "1.0.0.28", - "port-version": 1 + "baseline": "1.0.0.31", + "port-version": 0 }, "libwebp": { "baseline": "1.4.0", "port-version": 1 }, "libwebsockets": { - "baseline": "4.3.2", - "port-version": 0 + "baseline": "4.3.3", + "port-version": 1 }, "libx11": { "baseline": "1.8.1", @@ -5245,8 +5353,8 @@ "port-version": 0 }, "libxkbcommon": { - "baseline": "1.4.1", - "port-version": 1 + "baseline": "1.7.0", + "port-version": 0 }, "libxkbfile": { "baseline": "1.1.0", @@ -5257,7 +5365,7 @@ "port-version": 2 }, "libxml2": { - "baseline": "2.11.7", + "baseline": "2.11.9", "port-version": 0 }, "libxmlmm": { @@ -5302,7 +5410,7 @@ }, "libxslt": { "baseline": "1.1.37", - "port-version": 3 + "port-version": 4 }, "libxt": { "baseline": "1.3.0", @@ -5322,11 +5430,11 @@ }, "libyaml": { "baseline": "0.2.5", - "port-version": 4 + "port-version": 5 }, "libyuv": { - "baseline": "1857", - "port-version": 0 + "baseline": "1895", + "port-version": 1 }, "libzen": { "baseline": "0.4.41", @@ -5348,6 +5456,10 @@ "baseline": "2020-11-24", "port-version": 0 }, + "lightgbm": { + "baseline": "4.4.0", + "port-version": 1 + }, "lightningscanner": { "baseline": "1.0.1", "port-version": 0 @@ -5373,11 +5485,11 @@ "port-version": 0 }, "live555": { - "baseline": "2023-11-30", - "port-version": 1 + "baseline": "2024-06-26", + "port-version": 0 }, "llfio": { - "baseline": "2023-11-06", + "baseline": "2024-09-05", "port-version": 0 }, "llgi": { @@ -5397,15 +5509,15 @@ "port-version": 0 }, "llvm": { - "baseline": "17.0.2", - "port-version": 5 + "baseline": "18.1.6", + "port-version": 1 }, "lmdb": { - "baseline": "0.9.31", + "baseline": "0.9.33", "port-version": 0 }, "lockpp": { - "baseline": "2.6", + "baseline": "3.0", "port-version": 0 }, "lodepng": { @@ -5430,11 +5542,15 @@ }, "loguru": { "baseline": "2.1.0", - "port-version": 3 + "port-version": 4 }, "lpeg": { "baseline": "1.1.0", - "port-version": 0 + "port-version": 1 + }, + "ls-qpack": { + "baseline": "2.5.4", + "port-version": 3 }, "ltla-aarand": { "baseline": "2023-03-19", @@ -5461,7 +5577,7 @@ "port-version": 0 }, "lua": { - "baseline": "5.4.6", + "baseline": "5.4.7", "port-version": 0 }, "lua-compat53": { @@ -5478,7 +5594,7 @@ }, "luafilesystem": { "baseline": "1.8.0", - "port-version": 5 + "port-version": 6 }, "luajit": { "baseline": "2023-01-04", @@ -5497,11 +5613,11 @@ "port-version": 1 }, "lunarg-vulkantools": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "lunasvg": { - "baseline": "2.3.9", + "baseline": "2.4.1", "port-version": 0 }, "luv": { @@ -5513,8 +5629,8 @@ "port-version": 1 }, "lz4": { - "baseline": "1.9.4", - "port-version": 1 + "baseline": "1.10.0", + "port-version": 0 }, "lzav": { "baseline": "3.13", @@ -5537,20 +5653,20 @@ "port-version": 0 }, "magic-enum": { - "baseline": "0.9.5", - "port-version": 0 + "baseline": "0.9.6", + "port-version": 1 }, "magic-get": { "baseline": "2019-09-02", "port-version": 3 }, "magma": { - "baseline": "2.7.2", + "baseline": "2.8.0", "port-version": 0 }, "magnum": { "baseline": "2020.06", - "port-version": 17 + "port-version": 19 }, "magnum-extras": { "baseline": "2020.06", @@ -5562,7 +5678,7 @@ }, "magnum-plugins": { "baseline": "2020.06", - "port-version": 12 + "port-version": 13 }, "mailio": { "baseline": "0.23.0", @@ -5605,7 +5721,11 @@ "port-version": 0 }, "marble": { - "baseline": "24.02.0", + "baseline": "24.07.90", + "port-version": 0 + }, + "mariadb-connector-cpp": { + "baseline": "1.1.5", "port-version": 0 }, "marisa-trie": { @@ -5630,7 +5750,11 @@ }, "mathgl": { "baseline": "8.0.1", - "port-version": 5 + "port-version": 7 + }, + "mathter": { + "baseline": "2.0.0", + "port-version": 0 }, "matio": { "baseline": "1.5.26", @@ -5649,7 +5773,7 @@ "port-version": 2 }, "mbedtls": { - "baseline": "2.28.7", + "baseline": "3.6.1", "port-version": 0 }, "mchehab-zbar": { @@ -5660,6 +5784,10 @@ "baseline": "2.7.2.14", "port-version": 5 }, + "md4c": { + "baseline": "0.5.2", + "port-version": 0 + }, "mdl-sdk": { "baseline": "2021.1.2", "port-version": 5 @@ -5678,22 +5806,22 @@ }, "mecab": { "baseline": "2019-09-25", - "port-version": 5 + "port-version": 6 }, "memorymodule": { "baseline": "2019-12-31", "port-version": 3 }, "mesa": { - "baseline": "23.2.1", - "port-version": 1 + "baseline": "24.0.7", + "port-version": 2 }, "meschach": { "baseline": "1.2b", "port-version": 6 }, "meshoptimizer": { - "baseline": "0.20", + "baseline": "0.21", "port-version": 0 }, "metis": { @@ -5710,7 +5838,7 @@ }, "mfx-dispatch": { "baseline": "1.35.1", - "port-version": 3 + "port-version": 4 }, "mgnlibs": { "baseline": "2019-09-29", @@ -5720,9 +5848,17 @@ "baseline": "2.5.1", "port-version": 3 }, + "michaelmiller-sec21": { + "baseline": "1.0.1", + "port-version": 0 + }, + "micro-gl": { + "baseline": "2024-06-18", + "port-version": 0 + }, "microsoft-signalr": { "baseline": "0.1.0-alpha4", - "port-version": 8 + "port-version": 12 }, "mikktspace": { "baseline": "2020-10-06", @@ -5733,8 +5869,8 @@ "port-version": 6 }, "mimalloc": { - "baseline": "2.1.2", - "port-version": 2 + "baseline": "2.1.7", + "port-version": 0 }, "minc": { "baseline": "2.4.03", @@ -5757,7 +5893,7 @@ "port-version": 0 }, "minio-cpp": { - "baseline": "0.2.0", + "baseline": "0.3.0", "port-version": 0 }, "miniply": { @@ -5773,19 +5909,19 @@ "port-version": 0 }, "miniupnpc": { - "baseline": "2.2.6", + "baseline": "2.3.7", "port-version": 0 }, "miniz": { "baseline": "3.0.2", - "port-version": 0 + "port-version": 1 }, "minizip": { "baseline": "1.3.1", - "port-version": 0 + "port-version": 1 }, "minizip-ng": { - "baseline": "4.0.5", + "baseline": "4.0.7", "port-version": 0 }, "mio": { @@ -5793,7 +5929,7 @@ "port-version": 0 }, "mlpack": { - "baseline": "4.3.0", + "baseline": "4.4.0", "port-version": 0 }, "mman": { @@ -5810,7 +5946,7 @@ }, "mnn": { "baseline": "1.1.0", - "port-version": 5 + "port-version": 6 }, "modern-cpp-kafka": { "baseline": "2023.03.07", @@ -5821,20 +5957,20 @@ "port-version": 2 }, "mongo-c-driver": { - "baseline": "1.27.1", + "baseline": "1.28.0", "port-version": 0 }, "mongo-cxx-driver": { - "baseline": "3.10.1", - "port-version": 0 + "baseline": "3.10.2", + "port-version": 1 }, "mongoose": { - "baseline": "7.13", + "baseline": "7.15", "port-version": 0 }, "monkeys-audio": { "baseline": "10.08", - "port-version": 1 + "port-version": 2 }, "moos-core": { "baseline": "10.4.0", @@ -5858,15 +5994,15 @@ }, "mozjpeg": { "baseline": "4.1.5", - "port-version": 0 + "port-version": 1 }, "mp-units": { - "baseline": "2.1.0", + "baseline": "2.2.1", "port-version": 0 }, "mp3lame": { "baseline": "3.100", - "port-version": 13 + "port-version": 15 }, "mpark-patterns": { "baseline": "2019-10-03", @@ -5885,8 +6021,8 @@ "port-version": 0 }, "mpg123": { - "baseline": "1.31.3", - "port-version": 4 + "baseline": "1.32.7", + "port-version": 0 }, "mpi": { "baseline": "1", @@ -5924,17 +6060,13 @@ "baseline": "0.43.1", "port-version": 0 }, - "ms-quic": { - "baseline": "1.2.0", - "port-version": 0 - }, "msdfgen": { - "baseline": "1.11.0", + "baseline": "1.12", "port-version": 0 }, "msgpack": { - "baseline": "6.0.0", - "port-version": 1 + "baseline": "6.1.1", + "port-version": 0 }, "msgpack-c": { "baseline": "6.0.0", @@ -5944,6 +6076,10 @@ "baseline": "0.0.10", "port-version": 4 }, + "msh3": { + "baseline": "0.6.0", + "port-version": 0 + }, "msinttypes": { "baseline": "2018-02-25", "port-version": 2 @@ -5956,6 +6092,10 @@ "baseline": "10.1.12498", "port-version": 4 }, + "msquic": { + "baseline": "2.3.6", + "port-version": 2 + }, "mstch": { "baseline": "1.0.2", "port-version": 5 @@ -5989,7 +6129,7 @@ "port-version": 7 }, "mvfst": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "mygui": { @@ -5998,7 +6138,7 @@ }, "mysql-connector-cpp": { "baseline": "8.0.32", - "port-version": 1 + "port-version": 2 }, "nameof": { "baseline": "0.10.4", @@ -6025,7 +6165,7 @@ "port-version": 8 }, "nanoflann": { - "baseline": "1.5.1", + "baseline": "1.6.1", "port-version": 0 }, "nanogui": { @@ -6038,11 +6178,11 @@ }, "nanomsg": { "baseline": "1.2.1", - "port-version": 1 + "port-version": 2 }, "nanopb": { "baseline": "0.4.8", - "port-version": 0 + "port-version": 1 }, "nanoprintf": { "baseline": "0.3.4", @@ -6064,8 +6204,8 @@ "baseline": "2019-08-30", "port-version": 6 }, - "nativefiledialog": { - "baseline": "2022-01-20", + "nativefiledialog-extended": { + "baseline": "1.2.0", "port-version": 0 }, "nayuki-qr-code-generator": { @@ -6108,16 +6248,20 @@ "baseline": "4.3.1", "port-version": 5 }, + "netcpp": { + "baseline": "0.5.0", + "port-version": 0 + }, "netgen": { "baseline": "6.2.2401", - "port-version": 1 + "port-version": 2 }, "nethost": { "baseline": "8.0.3", "port-version": 0 }, "nettle": { - "baseline": "3.9.1", + "baseline": "3.10", "port-version": 0 }, "networkdirect-sdk": { @@ -6125,7 +6269,7 @@ "port-version": 4 }, "nghttp2": { - "baseline": "1.61.0", + "baseline": "1.62.1", "port-version": 0 }, "nghttp2-asio": { @@ -6133,16 +6277,16 @@ "port-version": 1 }, "nghttp3": { - "baseline": "1.1.0", - "port-version": 0 + "baseline": "1.5.0", + "port-version": 1 }, "ngspice": { "baseline": "41", "port-version": 0 }, "ngtcp2": { - "baseline": "1.2.0", - "port-version": 0 + "baseline": "1.7.0", + "port-version": 1 }, "nifly": { "baseline": "1.0.0", @@ -6158,7 +6302,7 @@ }, "nlohmann-json": { "baseline": "3.11.3", - "port-version": 0 + "port-version": 1 }, "nlopt": { "baseline": "2.7.1", @@ -6173,7 +6317,7 @@ "port-version": 1 }, "nng": { - "baseline": "1.7.3", + "baseline": "1.8.0", "port-version": 0 }, "nngpp": { @@ -6214,7 +6358,7 @@ }, "nss": { "baseline": "3.99", - "port-version": 0 + "port-version": 1 }, "nsync": { "baseline": "1.26.0", @@ -6242,12 +6386,16 @@ }, "numcpp": { "baseline": "2.12.1", - "port-version": 1 + "port-version": 2 }, "nuspell": { "baseline": "5.1.4", "port-version": 0 }, + "nvidia-cutlass": { + "baseline": "3.3.0", + "port-version": 0 + }, "nvtt": { "baseline": "2.1.2", "port-version": 8 @@ -6274,7 +6422,7 @@ }, "oatpp-mbedtls": { "baseline": "1.3.0", - "port-version": 0 + "port-version": 1 }, "oatpp-mongo": { "baseline": "1.3.0", @@ -6320,6 +6468,10 @@ "baseline": "4.7.6", "port-version": 0 }, + "octave": { + "baseline": "9.2.0", + "port-version": 1 + }, "octomap": { "baseline": "1.10.0", "port-version": 0 @@ -6338,7 +6490,7 @@ }, "ogre": { "baseline": "14.2.2", - "port-version": 0 + "port-version": 1 }, "ogre-next": { "baseline": "2.3.3", @@ -6350,19 +6502,19 @@ }, "omniorb": { "baseline": "4.3.0", - "port-version": 2 + "port-version": 3 }, "ompl": { "baseline": "1.6.0", - "port-version": 0 + "port-version": 2 }, "omplapp": { "baseline": "1.5.1", "port-version": 5 }, "onednn": { - "baseline": "3.4", - "port-version": 0 + "baseline": "3.5.3", + "port-version": 1 }, "oniguruma": { "baseline": "6.9.7.1", @@ -6377,7 +6529,7 @@ "port-version": 0 }, "onnxruntime-gpu": { - "baseline": "1.16.3", + "baseline": "1.19.2", "port-version": 0 }, "oof": { @@ -6389,24 +6541,24 @@ "port-version": 0 }, "open62541": { - "baseline": "1.3.9", + "baseline": "1.3.12", "port-version": 0 }, "open62541pp": { - "baseline": "0.12.0", + "baseline": "0.14.0", "port-version": 0 }, "openal-soft": { "baseline": "1.23.1", - "port-version": 0 + "port-version": 2 }, "openblas": { "baseline": "0.3.27", - "port-version": 0 + "port-version": 1 }, "opencascade": { "baseline": "7.8.1", - "port-version": 0 + "port-version": 1 }, "opencc": { "baseline": "1.1.6", @@ -6417,12 +6569,12 @@ "port-version": 2 }, "opencl": { - "baseline": "v2023.02.06", - "port-version": 2 + "baseline": "v2024.05.08", + "port-version": 0 }, "opencolorio": { "baseline": "2.2.1", - "port-version": 1 + "port-version": 3 }, "opencsg": { "baseline": "1.6.0", @@ -6442,19 +6594,19 @@ }, "opencv3": { "baseline": "3.4.18", - "port-version": 14 + "port-version": 16 }, "opencv4": { "baseline": "4.8.0", - "port-version": 19 + "port-version": 22 }, "opendnp3": { "baseline": "3.1.1", "port-version": 1 }, "openexr": { - "baseline": "3.2.3", - "port-version": 1 + "baseline": "3.2.4", + "port-version": 0 }, "openfbx": { "baseline": "2022-07-18", @@ -6481,15 +6633,15 @@ "port-version": 4 }, "openimageio": { - "baseline": "2.5.8.0", - "port-version": 3 + "baseline": "2.5.14.0", + "port-version": 0 }, "openjpeg": { "baseline": "2.5.2", "port-version": 1 }, "openldap": { - "baseline": "2.5.17", + "baseline": "2.5.18", "port-version": 0 }, "openmama": { @@ -6506,27 +6658,27 @@ }, "openmvg": { "baseline": "2.0", - "port-version": 10 + "port-version": 11 }, "openmvs": { "baseline": "2.1.0", - "port-version": 5 + "port-version": 6 }, "openni2": { "baseline": "2.2.0.33", "port-version": 15 }, "openscap": { - "baseline": "1.3.7", - "port-version": 2 + "baseline": "1.4.0", + "port-version": 1 }, "openslide": { "baseline": "3.4.1", "port-version": 4 }, "openssl": { - "baseline": "3.3.0", - "port-version": 0 + "baseline": "3.3.2", + "port-version": 1 }, "openssl-unix": { "baseline": "deprecated", @@ -6545,8 +6697,12 @@ "port-version": 2 }, "opentelemetry-cpp": { - "baseline": "1.14.2", - "port-version": 1 + "baseline": "1.16.1", + "port-version": 0 + }, + "opentelemetry-cpp-contrib-version": { + "baseline": "2024-06-17", + "port-version": 0 }, "opentracing": { "baseline": "1.6.0", @@ -6561,12 +6717,12 @@ "port-version": 0 }, "openvino": { - "baseline": "2024.1.0", + "baseline": "2024.3.0", "port-version": 0 }, "openvpn3": { - "baseline": "3.7.0", - "port-version": 2 + "baseline": "3.10", + "port-version": 1 }, "openvr": { "baseline": "2.5.1", @@ -6589,7 +6745,7 @@ "port-version": 0 }, "opus": { - "baseline": "1.5.1", + "baseline": "1.5.2", "port-version": 0 }, "opusfile": { @@ -6606,7 +6762,7 @@ }, "osg": { "baseline": "3.6.5", - "port-version": 23 + "port-version": 25 }, "osg-qt": { "baseline": "Qt5", @@ -6614,7 +6770,7 @@ }, "osgearth": { "baseline": "3.4", - "port-version": 1 + "port-version": 3 }, "osmanip": { "baseline": "4.6.1", @@ -6625,7 +6781,7 @@ "port-version": 0 }, "outcome": { - "baseline": "2.2.8", + "baseline": "2.2.9", "port-version": 0 }, "p-ranav-csv": { @@ -6645,8 +6801,8 @@ "port-version": 1 }, "paho-mqttpp3": { - "baseline": "1.3.2", - "port-version": 0 + "baseline": "1.4.1", + "port-version": 1 }, "palsigslot": { "baseline": "1.2.2", @@ -6673,8 +6829,8 @@ "port-version": 3 }, "paraview": { - "baseline": "5.12.0", - "port-version": 0 + "baseline": "5.12.1", + "port-version": 2 }, "parmetis": { "baseline": "2022-07-27", @@ -6684,6 +6840,10 @@ "baseline": "0", "port-version": 2 }, + "parsi": { + "baseline": "0.1.0", + "port-version": 0 + }, "parson": { "baseline": "2022-11-13", "port-version": 0 @@ -6693,8 +6853,8 @@ "port-version": 9 }, "pcapplusplus": { - "baseline": "23.9", - "port-version": 1 + "baseline": "24.9", + "port-version": 0 }, "pcg": { "baseline": "2021-04-06", @@ -6706,7 +6866,7 @@ }, "pcl": { "baseline": "1.14.1", - "port-version": 0 + "port-version": 1 }, "pcre": { "baseline": "8.45", @@ -6745,7 +6905,7 @@ "port-version": 3 }, "perfetto": { - "baseline": "45.0", + "baseline": "47.0", "port-version": 0 }, "pffft": { @@ -6761,7 +6921,7 @@ "port-version": 3 }, "phnt": { - "baseline": "2020-12-21", + "baseline": "2024-05-22", "port-version": 0 }, "physac": { @@ -6790,7 +6950,7 @@ }, "pipewire": { "baseline": "1.0.4", - "port-version": 0 + "port-version": 3 }, "pistache": { "baseline": "2021-03-31", @@ -6802,10 +6962,10 @@ }, "pixman": { "baseline": "0.43.4", - "port-version": 0 + "port-version": 1 }, "pkgconf": { - "baseline": "2.2.0", + "baseline": "2.3.0", "port-version": 0 }, "plasma-wayland-protocols": { @@ -6881,8 +7041,8 @@ "port-version": 0 }, "pocketpy": { - "baseline": "1.4.5", - "port-version": 0 + "baseline": "1.4.6", + "port-version": 1 }, "poco": { "baseline": "1.13.3", @@ -6901,7 +7061,7 @@ "port-version": 12 }, "polyhook2": { - "baseline": "2024-02-08", + "baseline": "2024-06-03", "port-version": 0 }, "polymorphic-value": { @@ -6912,6 +7072,10 @@ "baseline": "3.0.0", "port-version": 5 }, + "poolstl": { + "baseline": "0.3.5", + "port-version": 0 + }, "poppler": { "baseline": "24.3.0", "port-version": 1 @@ -6954,7 +7118,7 @@ }, "pqp": { "baseline": "1.3", - "port-version": 7 + "port-version": 8 }, "pravila00-enum-string": { "baseline": "2023-10-16", @@ -6969,16 +7133,16 @@ "port-version": 0 }, "presentmon": { - "baseline": "1.10.0", + "baseline": "2.1.1", "port-version": 0 }, "proj": { - "baseline": "9.4.0", - "port-version": 0 + "baseline": "9.4.1", + "port-version": 2 }, "projectm-eval": { "baseline": "1.0.0", - "port-version": 0 + "port-version": 1 }, "prometheus-cpp": { "baseline": "1.2.4", @@ -6989,12 +7153,12 @@ "port-version": 0 }, "protobuf": { - "baseline": "3.21.12", - "port-version": 2 + "baseline": "4.25.1", + "port-version": 1 }, "protobuf-c": { - "baseline": "1.4.1", - "port-version": 1 + "baseline": "1.5.0", + "port-version": 0 }, "protopuf": { "baseline": "2.2.1", @@ -7009,11 +7173,11 @@ "port-version": 0 }, "proxy": { - "baseline": "2.4.0", + "baseline": "3.0.0", "port-version": 0 }, "proxygen": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "psimd": { @@ -7053,20 +7217,20 @@ "port-version": 0 }, "pulsar-client-cpp": { - "baseline": "3.4.2", - "port-version": 2 + "baseline": "3.5.1", + "port-version": 1 }, "pulseaudio": { "baseline": "17.0", - "port-version": 0 + "port-version": 1 }, "pulzed-mini": { "baseline": "0.9.14", "port-version": 0 }, "pybind11": { - "baseline": "2.12.0", - "port-version": 1 + "baseline": "2.13.6", + "port-version": 0 }, "pystring": { "baseline": "1.1.4", @@ -7078,15 +7242,15 @@ }, "python3": { "baseline": "3.11.8", - "port-version": 2 + "port-version": 4 }, "qca": { "baseline": "2.3.7", - "port-version": 1 + "port-version": 2 }, "qcoro": { "baseline": "0.10.0", - "port-version": 0 + "port-version": 1 }, "qcustomplot": { "baseline": "2.1.1", @@ -7114,306 +7278,306 @@ }, "qpid-proton": { "baseline": "0.38.0", - "port-version": 1 + "port-version": 2 }, "qscintilla": { "baseline": "2.14.1", "port-version": 1 }, "qt": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qt-advanced-docking-system": { - "baseline": "4.3.0", + "baseline": "4.3.1", "port-version": 0 }, "qt3d": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qt5": { - "baseline": "5.15.13", - "port-version": 2 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-3d": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-activeqt": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-androidextras": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-base": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-canvas3d": { "baseline": "0", "port-version": 3 }, "qt5-charts": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-connectivity": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-datavis3d": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-declarative": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-doc": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-gamepad": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-graphicaleffects": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-imageformats": { - "baseline": "5.15.13", - "port-version": 2 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-location": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-macextras": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-modularscripts": { "baseline": "deprecated", "port-version": 1 }, "qt5-mqtt": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-multimedia": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-networkauth": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-purchasing": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-quickcontrols": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-quickcontrols2": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-remoteobjects": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-script": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-scxml": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-sensors": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-serialbus": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-serialport": { - "baseline": "5.15.13", + "baseline": "5.15.15", "port-version": 0 }, "qt5-speech": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-svg": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-tools": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-translations": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-virtualkeyboard": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-wayland": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-webchannel": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-webengine": { - "baseline": "5.15.13", - "port-version": 3 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-webglplugin": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-websockets": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-webview": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-winextras": { - "baseline": "5.15.13", - "port-version": 2 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-x11extras": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5-xmlpatterns": { - "baseline": "5.15.13", - "port-version": 1 + "baseline": "5.15.15", + "port-version": 0 }, "qt5compat": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtactiveqt": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtapplicationmanager": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtbase": { - "baseline": "6.7.0", - "port-version": 0 + "baseline": "6.7.2", + "port-version": 3 }, "qtcharts": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtcoap": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtconnectivity": { - "baseline": "6.7.0", - "port-version": 0 + "baseline": "6.7.2", + "port-version": 1 }, "qtdatavis3d": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtdeclarative": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtdeviceutilities": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtdoc": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtgraphs": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtgrpc": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qthttpserver": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtimageformats": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtinterfaceframework": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtkeychain": { - "baseline": "0.14.1", + "baseline": "0.14.3", "port-version": 0 }, "qtkeychain-qt6": { - "baseline": "0.14.1", - "port-version": 1 + "baseline": "0.14.3", + "port-version": 0 }, "qtlanguageserver": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtlocation": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtlottie": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtmqtt": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtmultimedia": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtnetworkauth": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtopcua": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtpositioning": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtquick3d": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtquick3dphysics": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtquickcontrols2": { @@ -7421,75 +7585,75 @@ "port-version": 1 }, "qtquickeffectmaker": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtquicktimeline": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtremoteobjects": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtscxml": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtsensors": { - "baseline": "6.7.0", - "port-version": 0 + "baseline": "6.7.2", + "port-version": 1 }, "qtserialbus": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtserialport": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtshadertools": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtspeech": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtsvg": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qttools": { - "baseline": "6.7.0", - "port-version": 0 + "baseline": "6.7.2", + "port-version": 1 }, "qttranslations": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtvirtualkeyboard": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtwayland": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtwebchannel": { - "baseline": "6.7.0", - "port-version": 0 + "baseline": "6.7.2", + "port-version": 1 }, "qtwebengine": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtwebsockets": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "qtwebview": { - "baseline": "6.7.0", + "baseline": "6.7.2", "port-version": 0 }, "quadtree": { @@ -7497,7 +7661,7 @@ "port-version": 0 }, "quantlib": { - "baseline": "1.34", + "baseline": "1.35", "port-version": 0 }, "quaternions": { @@ -7517,7 +7681,7 @@ "port-version": 9 }, "quill": { - "baseline": "3.8.0", + "baseline": "7.1.0", "port-version": 0 }, "quirc": { @@ -7554,22 +7718,26 @@ }, "range-v3": { "baseline": "0.12.0", - "port-version": 2 + "port-version": 4 }, "range-v3-vs2015": { "baseline": "20151130-vcpkg5", - "port-version": 2 + "port-version": 3 }, "rapidcheck": { "baseline": "2023-12-14", "port-version": 0 }, "rapidcsv": { - "baseline": "8.80", + "baseline": "8.83", "port-version": 0 }, "rapidfuzz": { - "baseline": "3.0.2", + "baseline": "3.0.5", + "port-version": 0 + }, + "rapidhash": { + "baseline": "2024-06-08", "port-version": 0 }, "rapidjson": { @@ -7594,22 +7762,22 @@ }, "raylib": { "baseline": "5.0", - "port-version": 0 + "port-version": 1 }, "rbdl": { "baseline": "3.3.0", - "port-version": 6 + "port-version": 7 }, "rbdl-orb": { "baseline": "3.2.0", "port-version": 2 }, "re2": { - "baseline": "2024-04-01", - "port-version": 2 + "baseline": "2024-07-02", + "port-version": 0 }, "reactiveplusplus": { - "baseline": "2.0.0", + "baseline": "2.1.1", "port-version": 0 }, "readerwriterqueue": { @@ -7636,6 +7804,10 @@ "baseline": "1.1.0a", "port-version": 4 }, + "realm-core": { + "baseline": "14.10.4", + "port-version": 0 + }, "realsense2": { "baseline": "2.54.2", "port-version": 2 @@ -7677,8 +7849,8 @@ "port-version": 2 }, "rest-rpc": { - "baseline": "0.07", - "port-version": 2 + "baseline": "0.12", + "port-version": 0 }, "restbed": { "baseline": "4.8", @@ -7686,7 +7858,7 @@ }, "restc-cpp": { "baseline": "0.10.0", - "port-version": 2 + "port-version": 3 }, "restclient-cpp": { "baseline": "2022-02-09", @@ -7713,8 +7885,8 @@ "port-version": 3 }, "ring-span-lite": { - "baseline": "0.6.0", - "port-version": 1 + "baseline": "0.7.0", + "port-version": 0 }, "rioki-glow": { "baseline": "0.2.1", @@ -7729,15 +7901,15 @@ "port-version": 0 }, "rmlui": { - "baseline": "5.1", + "baseline": "6.0", "port-version": 1 }, "rmqcpp": { "baseline": "1.0.0", - "port-version": 0 + "port-version": 1 }, "roaring": { - "baseline": "3.0.1", + "baseline": "4.1.3", "port-version": 0 }, "robin-hood-hashing": { @@ -7745,19 +7917,19 @@ "port-version": 0 }, "robin-map": { - "baseline": "1.2.2", + "baseline": "1.3.0", "port-version": 0 }, "robotraconteur": { - "baseline": "1.2.0", - "port-version": 1 + "baseline": "1.2.2", + "port-version": 0 }, "robotraconteur-companion": { - "baseline": "0.3.1", + "baseline": "0.4.1", "port-version": 0 }, "rocksdb": { - "baseline": "9.1.0", + "baseline": "9.6.1", "port-version": 0 }, "rpclib": { @@ -7790,7 +7962,7 @@ }, "rsocket": { "baseline": "2021.08.30.00", - "port-version": 4 + "port-version": 5 }, "rtabmap": { "baseline": "0.21.4.1", @@ -7829,7 +8001,7 @@ "port-version": 1 }, "rxqt": { - "baseline": "bb2138c", + "baseline": "d0b1535", "port-version": 1 }, "rxspencer": { @@ -7838,7 +8010,7 @@ }, "ryml": { "baseline": "0.5.0", - "port-version": 0 + "port-version": 1 }, "ryu": { "baseline": "2.0", @@ -7849,7 +8021,7 @@ "port-version": 0 }, "s2n": { - "baseline": "1.4.8", + "baseline": "1.4.16", "port-version": 0 }, "safeint": { @@ -7857,7 +8029,7 @@ "port-version": 0 }, "sail": { - "baseline": "0.9.4", + "baseline": "0.9.5", "port-version": 1 }, "sajson": { @@ -7878,11 +8050,11 @@ }, "sassc": { "baseline": "3.6.2", - "port-version": 0 + "port-version": 1 }, "saucer": { - "baseline": "2.1.0", - "port-version": 0 + "baseline": "2.3.0", + "port-version": 1 }, "sbp": { "baseline": "3.4.10", @@ -7893,8 +8065,8 @@ "port-version": 1 }, "scintilla": { - "baseline": "4.4.6", - "port-version": 3 + "baseline": "5.5.1", + "port-version": 0 }, "sciplot": { "baseline": "0.3.1", @@ -7905,12 +8077,12 @@ "port-version": 1 }, "sciter-js": { - "baseline": "5.0.3.0", + "baseline": "5.0.3.14", "port-version": 0 }, "scnlib": { - "baseline": "2.0.2", - "port-version": 2 + "baseline": "3.0.1", + "port-version": 0 }, "scope-guard": { "baseline": "1.1.0", @@ -7929,12 +8101,12 @@ "port-version": 3 }, "sdbus-cpp": { - "baseline": "1.5.0", + "baseline": "2.0.0", "port-version": 0 }, "sdformat10": { "baseline": "10.0.0", - "port-version": 4 + "port-version": 5 }, "sdformat13": { "baseline": "13.6.0", @@ -7942,11 +8114,11 @@ }, "sdformat6": { "baseline": "6.2.0", - "port-version": 7 + "port-version": 8 }, "sdformat9": { "baseline": "9.8.0", - "port-version": 2 + "port-version": 3 }, "sdl1": { "baseline": "1.2.15", @@ -7961,7 +8133,7 @@ "port-version": 6 }, "sdl2": { - "baseline": "2.30.1", + "baseline": "2.30.7", "port-version": 0 }, "sdl2-gfx": { @@ -7990,15 +8162,15 @@ }, "sdl2pp": { "baseline": "0.16.1", - "port-version": 8 + "port-version": 11 }, "seacas": { "baseline": "2022-11-22", - "port-version": 5 + "port-version": 7 }, "seal": { - "baseline": "4.1.1", - "port-version": 2 + "baseline": "4.1.2", + "port-version": 0 }, "seasocks": { "baseline": "1.4.6", @@ -8017,7 +8189,7 @@ "port-version": 0 }, "sentry-native": { - "baseline": "0.7.2", + "baseline": "0.7.9", "port-version": 0 }, "septag-dmon": { @@ -8040,6 +8212,10 @@ "baseline": "0.1.4.1", "port-version": 0 }, + "sese": { + "baseline": "2.2.0", + "port-version": 1 + }, "sf2cute": { "baseline": "0.2.0", "port-version": 4 @@ -8057,7 +8233,7 @@ "port-version": 0 }, "shader-slang": { - "baseline": "2024.1.12", + "baseline": "2024.11", "port-version": 0 }, "shaderc": { @@ -8069,15 +8245,15 @@ "port-version": 0 }, "shapelib": { - "baseline": "1.6.0", + "baseline": "1.6.1", "port-version": 0 }, "shiftmedia-libgcrypt": { "baseline": "1.10.3-1", - "port-version": 0 + "port-version": 1 }, "shiftmedia-libgnutls": { - "baseline": "3.7.6", + "baseline": "3.8.4", "port-version": 3 }, "shiftmedia-libgpg-error": { @@ -8089,8 +8265,8 @@ "port-version": 7 }, "shogun": { - "baseline": "6.1.4", - "port-version": 10 + "baseline": "2023-12-19", + "port-version": 1 }, "si": { "baseline": "2.5.1", @@ -8102,7 +8278,7 @@ }, "signalrclient": { "baseline": "1.0.0-beta1-9", - "port-version": 5 + "port-version": 6 }, "sigslot": { "baseline": "1.0.0", @@ -8114,22 +8290,22 @@ }, "simbody": { "baseline": "2023-01-10", - "port-version": 0 + "port-version": 1 }, "simd": { - "baseline": "5.3.128", - "port-version": 1 + "baseline": "6.1.140", + "port-version": 0 }, "simde": { "baseline": "0.8.2", "port-version": 0 }, "simdjson": { - "baseline": "3.8.0", + "baseline": "3.10.1", "port-version": 0 }, "simdutf": { - "baseline": "5.2.5", + "baseline": "5.5.0", "port-version": 0 }, "simonbrunel-qtpromise": { @@ -8149,7 +8325,7 @@ "port-version": 0 }, "simsimd": { - "baseline": "1.4.0", + "baseline": "5.4.1", "port-version": 0 }, "sjpeg": { @@ -8161,7 +8337,7 @@ "port-version": 0 }, "skia": { - "baseline": "124", + "baseline": "129", "port-version": 0 }, "skyr-url": { @@ -8178,26 +8354,30 @@ }, "slikenet": { "baseline": "2021-06-07", - "port-version": 2 + "port-version": 3 }, "sltbench": { "baseline": "2.4.0", "port-version": 3 }, + "small-gicp": { + "baseline": "1.0.0", + "port-version": 0 + }, "smf": { "baseline": "0.1.1", "port-version": 0 }, "smpeg2": { "baseline": "2.0.0", - "port-version": 10 + "port-version": 11 }, "snap7": { "baseline": "1.4.2", - "port-version": 1 + "port-version": 2 }, "snappy": { - "baseline": "1.1.10", + "baseline": "1.2.1", "port-version": 0 }, "sndfile": { @@ -8205,7 +8385,7 @@ "port-version": 2 }, "snitch": { - "baseline": "1.2.4", + "baseline": "1.2.5", "port-version": 0 }, "snowhouse": { @@ -8216,6 +8396,10 @@ "baseline": "1.6.1", "port-version": 0 }, + "soapysdr": { + "baseline": "0.8.1", + "port-version": 0 + }, "sobjectizer": { "baseline": "5.8.2", "port-version": 0 @@ -8230,7 +8414,7 @@ }, "sockpp": { "baseline": "1.0.0", - "port-version": 0 + "port-version": 1 }, "soem": { "baseline": "2023-06-09", @@ -8257,7 +8441,7 @@ "port-version": 2 }, "sophus": { - "baseline": "1.22.10", + "baseline": "1.24.6-r1", "port-version": 0 }, "soqt": { @@ -8278,7 +8462,7 @@ }, "spaceland": { "baseline": "7.8.2", - "port-version": 8 + "port-version": 9 }, "span-lite": { "baseline": "0.11.0", @@ -8328,6 +8512,10 @@ "baseline": "1.2.1", "port-version": 1 }, + "spglib": { + "baseline": "2.4.0", + "port-version": 0 + }, "spine-runtimes": { "baseline": "4.1.0", "port-version": 0 @@ -8337,19 +8525,19 @@ "port-version": 4 }, "spirv-cross": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "spirv-headers": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "spirv-reflect": { - "baseline": "1.3.280.0", - "port-version": 1 + "baseline": "1.3.290.0", + "port-version": 0 }, "spirv-tools": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "spout2": { @@ -8365,7 +8553,7 @@ "port-version": 3 }, "sqlcipher": { - "baseline": "4.5.6", + "baseline": "4.6.0", "port-version": 0 }, "sqlite-modern-cpp": { @@ -8374,14 +8562,14 @@ }, "sqlite-orm": { "baseline": "1.8.2", - "port-version": 1 + "port-version": 2 }, "sqlite3": { - "baseline": "3.45.3", + "baseline": "3.46.1", "port-version": 0 }, "sqlitecpp": { - "baseline": "3.3.1", + "baseline": "3.3.2", "port-version": 0 }, "sqlpp11": { @@ -8409,7 +8597,7 @@ "port-version": 0 }, "srpc": { - "baseline": "0.9.3", + "baseline": "0.10.1", "port-version": 0 }, "sse2neon": { @@ -8437,12 +8625,12 @@ "port-version": 3 }, "stb": { - "baseline": "2023-04-11", + "baseline": "2024-07-29", "port-version": 1 }, "stdexec": { - "baseline": "2023-09-06", - "port-version": 3 + "baseline": "2024-06-16", + "port-version": 2 }, "stduuid": { "baseline": "1.2.3", @@ -8454,11 +8642,15 @@ }, "stlab": { "baseline": "1.7.1", - "port-version": 1 + "port-version": 2 }, "stormlib": { - "baseline": "2019-05-10", - "port-version": 5 + "baseline": "9.26", + "port-version": 0 + }, + "str-view": { + "baseline": "0.5.0", + "port-version": 0 }, "strict-variant": { "baseline": "0.5", @@ -8469,7 +8661,7 @@ "port-version": 0 }, "string-view-lite": { - "baseline": "1.7.0", + "baseline": "1.8.0", "port-version": 1 }, "stringzilla": { @@ -8494,7 +8686,7 @@ }, "stxxl": { "baseline": "2018-11-15", - "port-version": 7 + "port-version": 8 }, "suitesparse": { "baseline": "5.8.0", @@ -8514,7 +8706,7 @@ }, "symengine": { "baseline": "0.11.2", - "port-version": 0 + "port-version": 2 }, "systemc": { "baseline": "2.3.3", @@ -8534,7 +8726,7 @@ }, "taglib": { "baseline": "2.0", - "port-version": 1 + "port-version": 2 }, "talib": { "baseline": "0.4.0", @@ -8542,7 +8734,7 @@ }, "taocpp-json": { "baseline": "2020-09-14", - "port-version": 3 + "port-version": 4 }, "tap-windows6": { "baseline": "9.21.2-0e30f5c", @@ -8553,11 +8745,11 @@ "port-version": 0 }, "taskflow": { - "baseline": "3.6.0", + "baseline": "3.7.0", "port-version": 0 }, "tbb": { - "baseline": "2021.11.0", + "baseline": "2021.13.0", "port-version": 0 }, "tcb-span": { @@ -8566,7 +8758,7 @@ }, "tcl": { "baseline": "core-9-0-a1", - "port-version": 6 + "port-version": 8 }, "tclap": { "baseline": "1.2.5", @@ -8576,9 +8768,13 @@ "baseline": "1.0.3", "port-version": 0 }, + "tdscpp": { + "baseline": "20240707", + "port-version": 0 + }, "telnetpp": { - "baseline": "2.1.2", - "port-version": 3 + "baseline": "3.1.0", + "port-version": 0 }, "tensorflow": { "baseline": "2.10.0", @@ -8590,7 +8786,7 @@ }, "tensorflow-common": { "baseline": "2.10.0", - "port-version": 2 + "port-version": 3 }, "tensorpipe": { "baseline": "2022-03-16", @@ -8601,7 +8797,11 @@ "port-version": 0 }, "tesseract": { - "baseline": "5.3.4", + "baseline": "5.4.1", + "port-version": 1 + }, + "tevclient": { + "baseline": "2023-12-04", "port-version": 0 }, "tfhe": { @@ -8637,7 +8837,7 @@ "port-version": 0 }, "thorvg": { - "baseline": "0.13.2", + "baseline": "0.14.10", "port-version": 0 }, "threadpool": { @@ -8646,7 +8846,7 @@ }, "thrift": { "baseline": "0.20.0", - "port-version": 0 + "port-version": 1 }, "tidy-html5": { "baseline": "5.8.0", @@ -8654,7 +8854,7 @@ }, "tiff": { "baseline": "4.6.0", - "port-version": 4 + "port-version": 5 }, "tinkerforge": { "baseline": "2.1.25", @@ -8693,7 +8893,7 @@ "port-version": 0 }, "tinyexif": { - "baseline": "2022-02-15", + "baseline": "2024-09-03", "port-version": 0 }, "tinyexpr": { @@ -8713,7 +8913,7 @@ "port-version": 0 }, "tinygltf": { - "baseline": "2.8.21", + "baseline": "2.9.3", "port-version": 0 }, "tinynpy": { @@ -8740,6 +8940,10 @@ "baseline": "1.1", "port-version": 6 }, + "tinytiff": { + "baseline": "4.0.1.0", + "port-version": 0 + }, "tinytoml": { "baseline": "20180219", "port-version": 3 @@ -8753,8 +8957,8 @@ "port-version": 10 }, "tinyxml2": { - "baseline": "9.0.0", - "port-version": 2 + "baseline": "10.0.0", + "port-version": 0 }, "tl-expected": { "baseline": "1.1.0", @@ -8790,10 +8994,10 @@ }, "tmxparser": { "baseline": "2019-10-14", - "port-version": 0 + "port-version": 1 }, "toml11": { - "baseline": "3.8.1", + "baseline": "4.2.0", "port-version": 0 }, "tomlplusplus": { @@ -8805,15 +9009,15 @@ "port-version": 4 }, "tracy": { - "baseline": "0.10.0", - "port-version": 2 + "baseline": "0.11.1", + "port-version": 1 }, "transwarp": { "baseline": "2.2.3", "port-version": 0 }, "trantor": { - "baseline": "1.5.18", + "baseline": "1.5.21", "port-version": 0 }, "tre": { @@ -8877,7 +9081,7 @@ "port-version": 3 }, "tvision": { - "baseline": "2024-02-28", + "baseline": "2024-05-22", "port-version": 0 }, "tweeny": { @@ -8885,11 +9089,11 @@ "port-version": 1 }, "type-lite": { - "baseline": "0.1.0", - "port-version": 3 + "baseline": "0.2.0", + "port-version": 0 }, "type-safe": { - "baseline": "0.2.3", + "baseline": "0.2.4", "port-version": 0 }, "uchardet": { @@ -8922,7 +9126,7 @@ }, "unittest-cpp": { "baseline": "2.0.0", - "port-version": 5 + "port-version": 6 }, "unixodbc": { "baseline": "2.3.11", @@ -8940,8 +9144,12 @@ "baseline": "7.0.7", "port-version": 0 }, + "upa-url": { + "baseline": "1.0.0", + "port-version": 0 + }, "upb": { - "baseline": "2022-06-21", + "baseline": "4.25.1", "port-version": 1 }, "urdfdom": { @@ -8957,7 +9165,7 @@ "port-version": 5 }, "uriparser": { - "baseline": "0.9.7", + "baseline": "0.9.8", "port-version": 0 }, "usbmuxd": { @@ -8978,10 +9186,10 @@ }, "usrsctp": { "baseline": "0.9.5.0", - "port-version": 3 + "port-version": 4 }, "utf8-range": { - "baseline": "2023-11-09", + "baseline": "4.25.1", "port-version": 0 }, "utf8h": { @@ -9006,10 +9214,10 @@ }, "uthenticode": { "baseline": "2.0.1", - "port-version": 0 + "port-version": 1 }, "uvatlas": { - "baseline": "2024-02-21", + "baseline": "2024-09-04", "port-version": 0 }, "uvw": { @@ -9017,7 +9225,7 @@ "port-version": 0 }, "uwebsockets": { - "baseline": "20.62.0", + "baseline": "20.65.0", "port-version": 0 }, "v-hacd": { @@ -9026,7 +9234,7 @@ }, "v8": { "baseline": "9.1.269.39", - "port-version": 7 + "port-version": 8 }, "valijson": { "baseline": "1.0.2", @@ -9049,25 +9257,29 @@ "port-version": 0 }, "vcglib": { - "baseline": "2022.02", + "baseline": "2023.12", "port-version": 0 }, "vcpkg-boost": { - "baseline": "2024-04-25", + "baseline": "2024-05-15", "port-version": 0 }, "vcpkg-cmake": { - "baseline": "2024-04-18", + "baseline": "2024-04-23", "port-version": 0 }, "vcpkg-cmake-config": { - "baseline": "2022-02-06", - "port-version": 1 + "baseline": "2024-05-23", + "port-version": 0 }, "vcpkg-cmake-get-vars": { "baseline": "2023-12-31", "port-version": 0 }, + "vcpkg-get-python": { + "baseline": "2024-06-08", + "port-version": 0 + }, "vcpkg-get-python-packages": { "baseline": "2024-01-24", "port-version": 0 @@ -9090,7 +9302,7 @@ }, "vcpkg-qmake": { "baseline": "2023-03-22", - "port-version": 1 + "port-version": 3 }, "vcpkg-tool-bazel": { "baseline": "5.2.0", @@ -9109,8 +9321,8 @@ "port-version": 1 }, "vcpkg-tool-meson": { - "baseline": "1.3.2", - "port-version": 2 + "baseline": "1.5.1", + "port-version": 0 }, "vcpkg-tool-mozbuild": { "baseline": "4.0.2", @@ -9133,7 +9345,7 @@ "port-version": 0 }, "veigar": { - "baseline": "1.0", + "baseline": "1.2", "port-version": 0 }, "velodyne-decoder": { @@ -9144,12 +9356,16 @@ "baseline": "1.4.0", "port-version": 0 }, + "via-httplib": { + "baseline": "1.9.0", + "port-version": 0 + }, "vili": { "baseline": "1.0.0+20221123", "port-version": 1 }, "vincentlaucsb-csv-parser": { - "baseline": "2.1.3", + "baseline": "2.2.3", "port-version": 0 }, "visit-struct": { @@ -9169,35 +9385,35 @@ "port-version": 0 }, "vladimirshaleev-ipaddress": { - "baseline": "1.0.1", + "baseline": "1.1.0", "port-version": 0 }, "vlfeat": { "baseline": "2020-07-10", - "port-version": 3 + "port-version": 4 }, "vlpp": { - "baseline": "1.1.0.0", - "port-version": 1 + "baseline": "1.2.9.0", + "port-version": 0 }, "volk": { - "baseline": "1.3.280.0", + "baseline": "1.3.295", "port-version": 0 }, "vowpal-wabbit": { - "baseline": "9.8.0", - "port-version": 2 + "baseline": "9.10.0", + "port-version": 0 }, "vs-yasm": { "baseline": "0.5.0", "port-version": 2 }, "vsg": { - "baseline": "1.1.2", + "baseline": "1.1.7", "port-version": 0 }, "vsgimgui": { - "baseline": "0.1.0", + "baseline": "0.3.0", "port-version": 0 }, "vsgxchange": { @@ -9205,8 +9421,8 @@ "port-version": 1 }, "vtk": { - "baseline": "9.3.0-pv5.12.0", - "port-version": 3 + "baseline": "9.3.0-pv5.12.1", + "port-version": 5 }, "vtk-dicom": { "baseline": "0.8.14", @@ -9221,39 +9437,39 @@ "port-version": 0 }, "vulkan-headers": { - "baseline": "1.3.280.0", - "port-version": 0 + "baseline": "1.3.290.0", + "port-version": 1 }, "vulkan-hpp": { "baseline": "deprecated", "port-version": 0 }, "vulkan-loader": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "vulkan-memory-allocator": { - "baseline": "3.0.1", - "port-version": 4 + "baseline": "3.1.0", + "port-version": 0 }, "vulkan-memory-allocator-hpp": { - "baseline": "3.0.1.1", - "port-version": 1 + "baseline": "3.1.0", + "port-version": 0 }, "vulkan-sdk-components": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "vulkan-tools": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "vulkan-utility-libraries": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "vulkan-validationlayers": { - "baseline": "1.3.280.0", + "baseline": "1.3.290.0", "port-version": 0 }, "vvenc": { @@ -9264,17 +9480,21 @@ "baseline": "2.0.2", "port-version": 6 }, + "wabt": { + "baseline": "1.0.36", + "port-version": 0 + }, "wampcc": { "baseline": "2019-09-04", "port-version": 5 }, "wangle": { - "baseline": "2024.05.06.00", + "baseline": "2024.09.16.00", "port-version": 0 }, "wasmedge": { "baseline": "0.13.5", - "port-version": 1 + "port-version": 2 }, "wavelib": { "baseline": "2021-11-26", @@ -9282,7 +9502,7 @@ }, "wavpack": { "baseline": "5.6.0", - "port-version": 1 + "port-version": 2 }, "wayland": { "baseline": "1.21.0", @@ -9310,14 +9530,14 @@ }, "wg21-linear-algebra": { "baseline": "0.7.3", - "port-version": 0 + "port-version": 1 }, "wg21-sg14": { "baseline": "2019-08-13", "port-version": 2 }, "wil": { - "baseline": "2024-01-22", + "baseline": "1.0.240803.1", "port-version": 0 }, "wildmidi": { @@ -9341,7 +9561,7 @@ "port-version": 0 }, "winreg": { - "baseline": "6.2.0", + "baseline": "6.3.0", "port-version": 0 }, "winsock2": { @@ -9365,16 +9585,16 @@ "port-version": 4 }, "wolfmqtt": { - "baseline": "1.16.0", + "baseline": "1.19.0", "port-version": 0 }, "wolfssl": { - "baseline": "5.7.0", - "port-version": 0 + "baseline": "5.7.2", + "port-version": 3 }, "wolftpm": { - "baseline": "2.7.0", - "port-version": 2 + "baseline": "3.4.0", + "port-version": 0 }, "wordnet": { "baseline": "3.0", @@ -9386,7 +9606,7 @@ }, "wpilib": { "baseline": "2023-08-24", - "port-version": 0 + "port-version": 1 }, "wren": { "baseline": "0.4.0", @@ -9409,8 +9629,8 @@ "port-version": 0 }, "wxwidgets": { - "baseline": "3.2.4", - "port-version": 2 + "baseline": "3.2.5", + "port-version": 3 }, "wyhash": { "baseline": "2023-12-03", @@ -9421,15 +9641,15 @@ "port-version": 0 }, "x264": { - "baseline": "0.164.3107", + "baseline": "0.164.3108", "port-version": 0 }, "x265": { - "baseline": "3.5", + "baseline": "3.6", "port-version": 0 }, "x86-simd-sort": { - "baseline": "4.0", + "baseline": "5.0", "port-version": 0 }, "xapian": { @@ -9438,19 +9658,19 @@ }, "xaudio2redist": { "baseline": "1.2.11", - "port-version": 2 + "port-version": 4 }, "xbitmaps": { "baseline": "1.1.2", "port-version": 0 }, "xbyak": { - "baseline": "6.73", + "baseline": "7.6", "port-version": 0 }, "xcb": { "baseline": "1.14", - "port-version": 1 + "port-version": 2 }, "xcb-image": { "baseline": "0.4.1", @@ -9505,7 +9725,7 @@ "port-version": 0 }, "xmlsec": { - "baseline": "1.3.3", + "baseline": "1.3.5", "port-version": 0 }, "xnnpack": { @@ -9514,7 +9734,7 @@ }, "xorg-macros": { "baseline": "1.19.3", - "port-version": 0 + "port-version": 1 }, "xorstr": { "baseline": "2021-11-20", @@ -9534,11 +9754,11 @@ }, "xqilla": { "baseline": "2.3.4", - "port-version": 2 + "port-version": 3 }, "xsimd": { - "baseline": "12.1.1", - "port-version": 0 + "baseline": "13.0.0", + "port-version": 1 }, "xtensor": { "baseline": "0.25.0", @@ -9562,7 +9782,7 @@ }, "xtrans": { "baseline": "1.4.0", - "port-version": 1 + "port-version": 2 }, "xxhash": { "baseline": "0.8.2", @@ -9577,8 +9797,8 @@ "port-version": 1 }, "yara": { - "baseline": "4.5.0", - "port-version": 0 + "baseline": "4.5.2", + "port-version": 1 }, "yas": { "baseline": "7.1.0", @@ -9601,15 +9821,15 @@ "port-version": 0 }, "yoga": { - "baseline": "3.0.2", + "baseline": "3.1.0", "port-version": 0 }, "yomm2": { - "baseline": "1.5.1", + "baseline": "1.5.2", "port-version": 0 }, "yyjson": { - "baseline": "0.8.0", + "baseline": "0.10.0", "port-version": 0 }, "z3": { @@ -9617,7 +9837,7 @@ "port-version": 0 }, "z4kn4fein-semver": { - "baseline": "0.2.1", + "baseline": "0.4.0", "port-version": 0 }, "z85": { @@ -9630,14 +9850,14 @@ }, "zeromq": { "baseline": "4.3.5", - "port-version": 1 + "port-version": 2 }, "zfp": { "baseline": "1.0.0", - "port-version": 1 + "port-version": 2 }, "zimpl": { - "baseline": "3.5.3", + "baseline": "3.6.1", "port-version": 0 }, "zint": { @@ -9654,14 +9874,14 @@ }, "zlib-ng": { "baseline": "2.1.5", - "port-version": 0 + "port-version": 1 }, "zlmediakit": { "baseline": "2024-03-30", - "port-version": 1 + "port-version": 3 }, "zoe": { - "baseline": "3.0", + "baseline": "3.1", "port-version": 0 }, "zookeeper": { @@ -9670,7 +9890,7 @@ }, "zopfli": { "baseline": "1.0.3", - "port-version": 3 + "port-version": 4 }, "zpp-bits": { "baseline": "4.4.17", @@ -9690,7 +9910,7 @@ }, "ztd-cuneicode": { "baseline": "2023-11-03", - "port-version": 0 + "port-version": 1 }, "ztd-encoding-tables": { "baseline": "2023-06-10", @@ -9710,26 +9930,26 @@ }, "ztd-text": { "baseline": "2023-11-03", - "port-version": 0 + "port-version": 1 }, "zug": { - "baseline": "2021-04-23", - "port-version": 1 + "baseline": "2024-04-26", + "port-version": 0 }, "zycore": { - "baseline": "1.3.0", - "port-version": 1 + "baseline": "1.5.0", + "port-version": 0 }, "zydis": { - "baseline": "4.0.0", - "port-version": 2 + "baseline": "4.1.0", + "port-version": 0 }, "zyre": { - "baseline": "2019-07-07", - "port-version": 5 + "baseline": "2024-04-10", + "port-version": 0 }, "zziplib": { - "baseline": "0.13.73", + "baseline": "0.13.78", "port-version": 0 } } diff --git a/vcpkg/versions/d-/dpp.json b/vcpkg/versions/d-/dpp.json index d5b64f737f..a9e40299c5 100644 --- a/vcpkg/versions/d-/dpp.json +++ b/vcpkg/versions/d-/dpp.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "190a206eddf272472a4668d756e0293096341f97", + "version": "10.0.31", + "port-version": 0 + }, { "git-tree": "2224384b8c94dc8993bee072c9f506ef17e6eef4", "version": "10.0.30", From 428e0f235d9946601ba7028741cf36e47f772bde Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Sun, 22 Sep 2024 13:28:16 +0000 Subject: [PATCH 33/99] [skip ci] version bump --- include/dpp/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/dpp/version.h b/include/dpp/version.h index 92941b5eee..d047704e86 100644 --- a/include/dpp/version.h +++ b/include/dpp/version.h @@ -22,9 +22,9 @@ #pragma once #if !defined(DPP_VERSION_LONG) -#define DPP_VERSION_LONG 0x00100031 -#define DPP_VERSION_SHORT 100031 -#define DPP_VERSION_TEXT "D++ 10.0.31 (19-May-2024)" +#define DPP_VERSION_LONG 0x00100032 +#define DPP_VERSION_SHORT 100032 +#define DPP_VERSION_TEXT "D++ 10.0.32 (22-Sep-2024)" #define DPP_VERSION_MAJOR ((DPP_VERSION_LONG & 0x00ff0000) >> 16) #define DPP_VERSION_MINOR ((DPP_VERSION_LONG & 0x0000ff00) >> 8) From b3affb2fecf06063f0fdf468aa649b6058110114 Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Sun, 22 Sep 2024 11:43:19 -0400 Subject: [PATCH 34/99] ci: more secure llvm19 install process (#1246) --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4037de4c00..1032bd8262 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-16, cpp: clang++, version: 16, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-17, cpp: clang++, version: 17, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: clang-18, cpp: clang++, version: 18, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: '', cpp: clang++, version: 19, cmake-flags: '-DDPP_CORO=ON -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++"', cpack: 'no', ctest: 'no', mold: 'yes', llvm-install: '19.1.0', name-extra: " libc++" } + - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: 'clang-19 libc++-19-dev libc++abi-19-dev', cpp: clang++, version: 19, cmake-flags: '-DDPP_CORO=ON -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-stdlib=libc++"', cpack: 'no', ctest: 'no', mold: 'yes', name-extra: ' libc++', llvm-apt: 'yes' } # g++ - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-13, cpp: g++, version: 13, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } - { arch: 'amd64', concurrency: 4, os: ubuntu-24.04, package: g++-14, cpp: g++, version: 14, cmake-flags: '-DDPP_CORO=ON', cpack: 'no', ctest: 'no', mold: 'yes' } @@ -76,12 +76,12 @@ jobs: if: ${{ matrix.cfg.mold == 'yes' }} uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 - - name: Install LLVM - if: ${{ matrix.cfg.llvm-install != '' }} + - name: Add LLVM apt repository + if: ${{ matrix.cfg.llvm-apt }} run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.cfg.version }} all + osname=`cat /etc/os-release | grep -e "^VERSION_CODENAME" | cut -d= -f2` + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-add-repository -y "deb http://apt.llvm.org/$osname/ llvm-toolchain-$osname-${{ matrix.cfg.version }} main" - name: Install apt packages run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y ${{ matrix.cfg.package }} pkg-config libsodium-dev libopus-dev zlib1g-dev rpm From 6115edd8921f0559b69811ec7f0001c7b382394a Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Mon, 23 Sep 2024 09:20:33 +0000 Subject: [PATCH 35/99] feat: message forwarding --- include/dpp/message.h | 32 ++++++++++++++++++++++++++++++-- src/dpp/message.cpp | 10 +++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/include/dpp/message.h b/include/dpp/message.h index 60588e11a8..44640af8d8 100644 --- a/include/dpp/message.h +++ b/include/dpp/message.h @@ -2011,6 +2011,24 @@ namespace cache_policy { }; /** + * @brief Message Reference type + */ +enum DPP_EXPORT message_ref_type : uint8_t { + /** + * A reply or crosspost + */ + mrt_default = 0, + /** + * A forwarded message + */ + mrt_forward = 1, +}; + +template struct message_snapshot { + std::vector messages; +}; + + /** * @brief Represents messages sent and received on Discord */ struct DPP_EXPORT message : public managed, json_interface { @@ -2140,6 +2158,10 @@ struct DPP_EXPORT message : public managed, json_interface { * @brief Reference to another message, e.g. a reply */ struct message_ref { + /** + * @brief Message reference type, set to 1 to forward a message + */ + message_ref_type type{mrt_default}; /** * @brief ID of the originating message. */ @@ -2162,10 +2184,15 @@ struct DPP_EXPORT message : public managed, json_interface { bool fail_if_not_exists; } message_reference; + /** + * @brief Message snapshots for a forwarded message + */ + message_snapshot message_snapshots; + /** * @brief Reference to an interaction */ - struct message_interaction_struct{ + struct message_interaction_struct { /** * @brief ID of the interaction. */ @@ -2342,9 +2369,10 @@ struct DPP_EXPORT message : public managed, json_interface { * @param _guild_id guild id to reply to (optional) * @param _channel_id channel id to reply to (optional) * @param fail_if_not_exists true if the message send should fail if these values are invalid (optional) + * @param type Type of reference * @return message& reference to self */ - message& set_reference(snowflake _message_id, snowflake _guild_id = 0, snowflake _channel_id = 0, bool fail_if_not_exists = false); + message& set_reference(snowflake _message_id, snowflake _guild_id = 0, snowflake _channel_id = 0, bool fail_if_not_exists = false, message_ref_type type = mrt_default); /** * @brief Set the allowed mentions object for pings on the message diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index 6d416f0abb..d31661f0eb 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -677,11 +677,12 @@ message::message(class cluster* o) : message() { owner = o; } -message& message::set_reference(snowflake _message_id, snowflake _guild_id, snowflake _channel_id, bool fail_if_not_exists) { +message& message::set_reference(snowflake _message_id, snowflake _guild_id, snowflake _channel_id, bool fail_if_not_exists, message_ref_type type) { message_reference.channel_id = _channel_id; message_reference.guild_id = _guild_id; message_reference.message_id = _message_id; message_reference.fail_if_not_exists = fail_if_not_exists; + message_reference.type = type; return *this; } @@ -1408,10 +1409,17 @@ message& message::fill_from_json(json* d, cache_policy_t cp) { } if (d->find("message_reference") != d->end()) { json& mr = (*d)["message_reference"]; + message_reference.type = (message_ref_type)int8_not_null(&mr, "type"); message_reference.channel_id = snowflake_not_null(&mr, "channel_id"); message_reference.guild_id = snowflake_not_null(&mr, "guild_id"); message_reference.message_id = snowflake_not_null(&mr, "message_id"); message_reference.fail_if_not_exists = bool_not_null(&mr, "fail_if_not_exists"); + + if (message_reference.type == mrt_forward) { + for (auto& e : (*d)["message_snapshots"]) { + message_snapshots.messages.emplace_back(message().fill_from_json(e["message"], cp)); + } + } } if (auto it = d->find("poll"); it != d->end()) { from_json(*it, attached_poll.emplace()); From 78d8d119722333742fde218f7b628db4869725bc Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Mon, 23 Sep 2024 09:21:51 +0000 Subject: [PATCH 36/99] fix: forgot pointer --- src/dpp/message.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index d31661f0eb..044bbcddc9 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -1417,7 +1417,7 @@ message& message::fill_from_json(json* d, cache_policy_t cp) { if (message_reference.type == mrt_forward) { for (auto& e : (*d)["message_snapshots"]) { - message_snapshots.messages.emplace_back(message().fill_from_json(e["message"], cp)); + message_snapshots.messages.emplace_back(message().fill_from_json(&(e["message"]), cp)); } } } From 8773feed0f7c97e9b39e98f83517878869b68798 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Mon, 23 Sep 2024 10:34:53 +0000 Subject: [PATCH 37/99] fix: send type when building message --- src/dpp/message.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index 044bbcddc9..8c7efa1fe4 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -1120,6 +1120,7 @@ json message::to_json(bool with_id, bool is_interaction_response) const { /* Populate message reference */ if (message_reference.channel_id || message_reference.guild_id || message_reference.message_id) { j["message_reference"] = json::object(); + j["message_reference"]["type"] = static_cast(message_reference.type); if (message_reference.channel_id) { j["message_reference"]["channel_id"] = std::to_string(message_reference.channel_id); } @@ -1409,7 +1410,7 @@ message& message::fill_from_json(json* d, cache_policy_t cp) { } if (d->find("message_reference") != d->end()) { json& mr = (*d)["message_reference"]; - message_reference.type = (message_ref_type)int8_not_null(&mr, "type"); + message_reference.type = static_cast(int8_not_null(&mr, "type")); message_reference.channel_id = snowflake_not_null(&mr, "channel_id"); message_reference.guild_id = snowflake_not_null(&mr, "guild_id"); message_reference.message_id = snowflake_not_null(&mr, "message_id"); From 2358d88611c9792885bd2b1eff932fb6836d32a8 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Tue, 24 Sep 2024 12:36:14 +0000 Subject: [PATCH 38/99] bump audio version to v8 from v4 --- src/dpp/discordvoiceclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index e46d4258a0..43d0f954a8 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -303,7 +303,7 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour } discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host) - : websocket_client(_host.substr(0, _host.find(":")), _host.substr(_host.find(":") + 1, _host.length()), "/?v=4", OP_TEXT), + : websocket_client(_host.substr(0, _host.find(":")), _host.substr(_host.find(":") + 1, _host.length()), "/?v=8", OP_TEXT), runner(nullptr), connect_time(0), mixer(std::make_unique()), From 2a594ecf15b60ce882f42776c809b452a20fdad9 Mon Sep 17 00:00:00 2001 From: Ruslan <79337999+ruslan-ilesik@users.noreply.github.com> Date: Sun, 29 Sep 2024 12:03:01 +0200 Subject: [PATCH 39/99] Docs: Fix embeds.cpp not required intent + add cout logger (#1250) --- docpages/example_code/embeds.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docpages/example_code/embeds.cpp b/docpages/example_code/embeds.cpp index 594b2a1861..f5e8e51fbd 100644 --- a/docpages/example_code/embeds.cpp +++ b/docpages/example_code/embeds.cpp @@ -2,7 +2,9 @@ int main() { /* Setup the bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); + + bot.on_log(dpp::utility::cout_logger()); /* The event is fired when someone issues your commands */ bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { From d43239f5e34d084d2fcf8a32cdd6114540d4ba50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DJ=3A=3A=C3=96tzi?= <58144390+DJOetzi@users.noreply.github.com> Date: Sun, 29 Sep 2024 17:28:53 +0200 Subject: [PATCH 40/99] docs: Remove coroutine/DPP_CORO experimental warnings (#1221) --- CMakeLists.txt | 2 +- docpages/include/coro_warn.dox | 2 +- library/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2e7a58f2d..874453a74c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ option(RUN_LDCONFIG "Run ldconfig after installation" ON) option(DPP_INSTALL "Generate the install target" ON) option(DPP_BUILD_TEST "Build the test program" ON) option(DPP_NO_VCPKG "No VCPKG" OFF) -option(DPP_CORO "Experimental support for C++20 coroutines" OFF) +option(DPP_CORO "Support for C++20 coroutines" OFF) option(DPP_FORMATTERS "Support for C++20 formatters" OFF) option(DPP_USE_EXTERNAL_JSON "Use an external installation of nlohmann::json" OFF) option(DPP_USE_PCH "Use precompiled headers to speed up compilation" OFF) diff --git a/docpages/include/coro_warn.dox b/docpages/include/coro_warn.dox index 2bf9097b71..5710006205 100644 --- a/docpages/include/coro_warn.dox +++ b/docpages/include/coro_warn.dox @@ -1 +1 @@ -\warning D++ Coroutines are a very new feature and are currently only supported by D++ on g++ 13, clang/LLVM 14, and MSVC 19.37 or above. Additionally, D++ must be built with the CMake option DPP_CORO, and your program must both define the macro DPP_CORO and use C++20 or above. The feature is experimental and may have bugs or even crashes, please report any to GitHub Issues or to our Discord Server. +\warning D++ Coroutines are a very new feature and are currently only supported by D++ on g++ 13, clang/LLVM 14, and MSVC 19.37 or above. Additionally, D++ must be built with the CMake option DPP_CORO, and your program must both define the macro DPP_CORO and use C++20 or above. diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 00b2a8b651..bc61c77723 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -289,7 +289,7 @@ if(HAVE_PTHREAD_SETNAME_NP) endif() if(DPP_CORO) - message("-- ${Yellow}Enabled experimental coroutine feature${ColourReset}") + message("-- ${Yellow}Enabled coroutine feature${ColourReset}") set(CMAKE_CXX_STANDARD 20) target_compile_features(dpp PUBLIC cxx_std_20) if(WIN32 AND NOT MINGW AND NOT DPP_CLANG_CL) From 9856694fce3cfbae895fbe6531598b70414715c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:24:44 +0000 Subject: [PATCH 41/99] build(deps): bump doxygen-awesome-css from `4593c19` to `568f56c` Bumps [doxygen-awesome-css](https://github.com/jothepro/doxygen-awesome-css) from `4593c19` to `568f56c`. - [Release notes](https://github.com/jothepro/doxygen-awesome-css/releases) - [Commits](https://github.com/jothepro/doxygen-awesome-css/compare/4593c198030b6e5019aae4d9c2eeb7497f02dbf8...568f56cde6ac78b6dfcc14acd380b2e745c301ea) --- updated-dependencies: - dependency-name: doxygen-awesome-css dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- doxygen-awesome-css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen-awesome-css b/doxygen-awesome-css index 4593c19803..568f56cde6 160000 --- a/doxygen-awesome-css +++ b/doxygen-awesome-css @@ -1 +1 @@ -Subproject commit 4593c198030b6e5019aae4d9c2eeb7497f02dbf8 +Subproject commit 568f56cde6ac78b6dfcc14acd380b2e745c301ea From af4c89f0fda5ed1d850ba32787a0e2e89e79a3e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:30:20 +0000 Subject: [PATCH 42/99] build(deps): bump docker/build-push-action from 6.7.0 to 6.9.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.7.0 to 6.9.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/5cd11c3a4ced054e52742c5fd54dca954e0edd85...4f58ea79222b3b9dc2c8bbdd6debcef730109a75) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 43dc7645f3..1ceb3da716 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 # v6.7.0 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: push: true tags: brainboxdotcc/dpp From d2f95c69931a027f18495cd62921a44cb084fc0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:30:26 +0000 Subject: [PATCH 43/99] build(deps): bump github/codeql-action from 3.25.11 to 3.26.10 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.25.11 to 3.26.10. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/b611370bb5703a7efb587f9d136a52ea24c5c38c...e2b3eafc8d227b0241d48be5f425d47c2d750a13) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f5883fc789..1bcfea1f72 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 + uses: github/codeql-action/init@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -64,6 +64,6 @@ jobs: run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release && cmake --build build -j4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 + uses: github/codeql-action/analyze@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a42bd6de20..1a69d2b519 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -72,6 +72,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 + uses: github/codeql-action/upload-sarif@e2b3eafc8d227b0241d48be5f425d47c2d750a13 # v3.26.10 with: sarif_file: results.sarif From 7405d60447513dac0eaead168a07dc71ce0ed7c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:30:31 +0000 Subject: [PATCH 44/99] build(deps): bump actions/checkout from 4.1.7 to 4.2.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 4.2.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/692973e3d937129bcbf40652eb9f2f61becf3332...d632683dd7b4114ad314bca15554477dd762a938) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql.yml | 2 +- .github/workflows/construct-vcpkg-info.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/documentation-check.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/gitguardian.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/test-docs-examples.yml | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1032bd8262..3b034bcd83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Setup mold if: ${{ matrix.cfg.mold == 'yes' }} @@ -142,7 +142,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Update Xcode uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 @@ -196,7 +196,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: path: main @@ -261,7 +261,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Install Packages run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y cmake rpm diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f5883fc789..a2a32fab78 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,7 +46,7 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/construct-vcpkg-info.yml b/.github/workflows/construct-vcpkg-info.yml index 17e23fc404..fb93c393b3 100644 --- a/.github/workflows/construct-vcpkg-info.yml +++ b/.github/workflows/construct-vcpkg-info.yml @@ -25,7 +25,7 @@ jobs: php-version: '8.1' - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: submodules: recursive diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 56d5770ba5..59eea8f943 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -22,6 +22,6 @@ jobs: egress-policy: audit - name: 'Checkout Repository' - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: 'Dependency Review' uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 diff --git a/.github/workflows/documentation-check.yml b/.github/workflows/documentation-check.yml index f4fb32f6b1..b6b0f661dd 100644 --- a/.github/workflows/documentation-check.yml +++ b/.github/workflows/documentation-check.yml @@ -27,7 +27,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Check docs spelling run: npx -y cspell lint --language-id=cpp --no-progress --no-summary --show-context --show-suggestions --relative --color docpages/*.md include/dpp/*.h diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 30a9cf5446..4a8757cb87 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -35,7 +35,7 @@ jobs: php-version: '8.0' - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: submodules: recursive diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index b03592b7af..74fbf5fcec 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -19,7 +19,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: fetch-depth: 0 # fetch all history so multiple commits can be scanned - name: GitGuardian scan diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a42bd6de20..d35cedcddb 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: egress-policy: audit - name: "Checkout code" - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: persist-credentials: false diff --git a/.github/workflows/test-docs-examples.yml b/.github/workflows/test-docs-examples.yml index 6f3356281d..4b5dfb4758 100644 --- a/.github/workflows/test-docs-examples.yml +++ b/.github/workflows/test-docs-examples.yml @@ -30,7 +30,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: submodules: recursive From fadfffa3fc0c42a8fe6bf61fecf5a652dffbe569 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:30:34 +0000 Subject: [PATCH 45/99] build(deps): bump GitGuardian/ggshield-action from 1.26.0 to 1.32.0 Bumps [GitGuardian/ggshield-action](https://github.com/gitguardian/ggshield-action) from 1.26.0 to 1.32.0. - [Release notes](https://github.com/gitguardian/ggshield-action/releases) - [Commits](https://github.com/gitguardian/ggshield-action/compare/3af6bd67c964cffe01a0f8f5c0dd04b8cda99e6b...53910b10ce6646fb7c6e353f55f26ed96d0cff1b) --- updated-dependencies: - dependency-name: GitGuardian/ggshield-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/gitguardian.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index b03592b7af..cccfbfecd8 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -23,7 +23,7 @@ jobs: with: fetch-depth: 0 # fetch all history so multiple commits can be scanned - name: GitGuardian scan - uses: GitGuardian/ggshield-action@3af6bd67c964cffe01a0f8f5c0dd04b8cda99e6b # master + uses: GitGuardian/ggshield-action@53910b10ce6646fb7c6e353f55f26ed96d0cff1b # master env: GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} GITHUB_PUSH_BASE_SHA: ${{ github.event.base }} From f1162bee096a3b7b0ac54224b07aed4f00b105a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:30:36 +0000 Subject: [PATCH 46/99] build(deps): bump ossf/scorecard-action from 2.3.3 to 2.4.0 Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.3.3 to 2.4.0. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/dc50aa9510b46c811795eb24b2f1ba02a914e534...62b2cac7ed8198b15735ed49ab1e5cf35480ba46) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a42bd6de20..f2007967d6 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -42,7 +42,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif From 753e67e7dfbde4c3523ebc1bfcf9c9c36c573841 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 11:35:12 +0000 Subject: [PATCH 47/99] build(deps): bump ubuntu from `dfc1087` to `b359f10` Bumps ubuntu from `dfc1087` to `b359f10`. --- updated-dependencies: - dependency-name: ubuntu dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4ea70e3e91..780c2e2af9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a +FROM ubuntu:noble@sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libsodium-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From c5c57e214a3ca70c6089c7ccf9c4089d3f5f79e2 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Mon, 7 Oct 2024 16:10:42 +0100 Subject: [PATCH 48/99] feat: Discord DAVE Protocol (E2EE) for voice (#1258) Co-authored-by: Neko-Life --- .cspell.json | 7 +- CMakeLists.txt | 6 + README.md | 14 +- cmake/FindFilesystem.cmake | 247 ++ docpages/advanced_reference/unit_tests.md | 7 + docpages/advanced_reference/voice_model.md | 57 + docpages/images/audioframe.svg | 228 ++ docpages/make_a_bot/cmake.md | 2 +- doxygen-awesome-css | 2 +- include/dpp/cluster.h | 11 +- include/dpp/discordclient.h | 16 +- include/dpp/discordvoiceclient.h | 225 +- include/dpp/dispatcher.h | 38 + include/dpp/guild.h | 4 +- include/dpp/isa/avx.h | 2 + include/dpp/isa/avx2.h | 2 + include/dpp/isa/avx512.h | 2 + include/dpp/isa/fallback.h | 2 + include/dpp/isa/neon.h | 2 + include/dpp/sslclient.h | 2 +- include/dpp/utility.h | 2 +- include/dpp/wsclient.h | 14 +- library-vcpkg/CMakeLists.txt | 54 +- library/CMakeLists.txt | 50 +- mlspp/CMakeLists.txt | 117 + mlspp/LICENSE | 25 + mlspp/cmake/config.cmake.in | 4 + mlspp/cmake/namespace.h.in | 4 + mlspp/include/mls/common.h | 274 ++ mlspp/include/mls/core_types.h | 380 +++ mlspp/include/mls/credential.h | 228 ++ mlspp/include/mls/crypto.h | 266 ++ mlspp/include/mls/key_schedule.h | 205 ++ mlspp/include/mls/messages.h | 752 +++++ mlspp/include/mls/session.h | 98 + mlspp/include/mls/state.h | 431 +++ mlspp/include/mls/tree_math.h | 107 + mlspp/include/mls/treekem.h | 255 ++ mlspp/include/namespace.h | 4 + mlspp/include/version.h | 5 + mlspp/lib/CMakeLists.txt | 4 + mlspp/lib/bytes/CMakeLists.txt | 25 + mlspp/lib/bytes/include/bytes/bytes.h | 127 + mlspp/lib/bytes/include/tls/compat.h | 61 + mlspp/lib/bytes/include/tls/tls_syntax.h | 569 ++++ mlspp/lib/bytes/src/bytes.cpp | 146 + mlspp/lib/hpke/CMakeLists.txt | 57 + mlspp/lib/hpke/include/hpke/base64.h | 20 + mlspp/lib/hpke/include/hpke/certificate.h | 75 + mlspp/lib/hpke/include/hpke/digest.h | 37 + mlspp/lib/hpke/include/hpke/hpke.h | 253 ++ mlspp/lib/hpke/include/hpke/random.h | 11 + mlspp/lib/hpke/include/hpke/signature.h | 89 + mlspp/lib/hpke/include/hpke/userinfo_vc.h | 82 + mlspp/lib/hpke/src/aead_cipher.cpp | 321 +++ mlspp/lib/hpke/src/aead_cipher.h | 45 + mlspp/lib/hpke/src/base64.cpp | 105 + mlspp/lib/hpke/src/certificate.cpp | 539 ++++ mlspp/lib/hpke/src/common.cpp | 20 + mlspp/lib/hpke/src/common.h | 10 + mlspp/lib/hpke/src/dhkem.cpp | 216 ++ mlspp/lib/hpke/src/dhkem.h | 57 + mlspp/lib/hpke/src/digest.cpp | 187 ++ mlspp/lib/hpke/src/group.cpp | 1077 +++++++ mlspp/lib/hpke/src/group.h | 116 + mlspp/lib/hpke/src/hkdf.cpp | 79 + mlspp/lib/hpke/src/hkdf.h | 24 + mlspp/lib/hpke/src/hpke.cpp | 540 ++++ mlspp/lib/hpke/src/openssl_common.cpp | 160 ++ mlspp/lib/hpke/src/openssl_common.h | 25 + mlspp/lib/hpke/src/random.cpp | 19 + mlspp/lib/hpke/src/rsa.cpp | 207 ++ mlspp/lib/hpke/src/rsa.h | 97 + mlspp/lib/hpke/src/signature.cpp | 344 +++ mlspp/lib/hpke/src/userinfo_vc.cpp | 401 +++ mlspp/lib/mls_vectors/CMakeLists.txt | 24 + .../include/mls_vectors/mls_vectors.h | 577 ++++ mlspp/lib/mls_vectors/src/mls_vectors.cpp | 2052 ++++++++++++++ mlspp/lib/tls_syntax/CMakeLists.txt | 21 + mlspp/lib/tls_syntax/include/tls/compat.h | 61 + mlspp/lib/tls_syntax/include/tls/tls_syntax.h | 569 ++++ mlspp/lib/tls_syntax/src/tls_syntax.cpp | 178 ++ mlspp/src/common.cpp | 13 + mlspp/src/core_types.cpp | 443 +++ mlspp/src/credential.cpp | 298 ++ mlspp/src/crypto.cpp | 498 ++++ mlspp/src/grease.cpp | 126 + mlspp/src/grease.h | 13 + mlspp/src/key_schedule.cpp | 579 ++++ mlspp/src/messages.cpp | 947 +++++++ mlspp/src/session.cpp | 437 +++ mlspp/src/state.cpp | 2219 +++++++++++++++ mlspp/src/tree_math.cpp | 223 ++ mlspp/src/treekem.cpp | 1127 ++++++++ src/davetest/dave.cpp | 85 + src/dpp/cluster.cpp | 5 + src/dpp/dave/array_view.h | 115 + src/dpp/dave/cipher_interface.cpp | 38 + src/dpp/dave/cipher_interface.h | 103 + src/dpp/dave/clock.h | 78 + src/dpp/dave/codec_utils.cpp | 427 +++ src/dpp/dave/codec_utils.h | 96 + src/dpp/dave/common.h | 168 ++ src/dpp/dave/cryptor_manager.cpp | 199 ++ src/dpp/dave/cryptor_manager.h | 172 ++ src/dpp/dave/decryptor.cpp | 233 ++ src/dpp/dave/decryptor.h | 200 ++ src/dpp/dave/encryptor.cpp | 299 ++ src/dpp/dave/encryptor.h | 254 ++ src/dpp/dave/frame_processors.cpp | 388 +++ src/dpp/dave/frame_processors.h | 298 ++ src/dpp/dave/key_ratchet.h | 64 + src/dpp/dave/leb128.cpp | 85 + src/dpp/dave/leb128.h | 69 + src/dpp/dave/mls_key_ratchet.cpp | 56 + src/dpp/dave/mls_key_ratchet.h | 79 + src/dpp/dave/openssl_aead_cipher.cpp | 160 ++ src/dpp/dave/openssl_aead_cipher.h | 99 + src/dpp/dave/parameters.cpp | 79 + src/dpp/dave/parameters.h | 85 + src/dpp/dave/persisted_key_pair.cpp | 103 + src/dpp/dave/persisted_key_pair.h | 123 + src/dpp/dave/persisted_key_pair_generic.cpp | 188 ++ src/dpp/dave/scope_exit.h | 103 + src/dpp/dave/session.cpp | 759 +++++ src/dpp/dave/session.h | 286 ++ src/dpp/dave/user_credential.cpp | 53 + src/dpp/dave/user_credential.h | 51 + src/dpp/dave/util.cpp | 54 + src/dpp/dave/util.h | 48 + src/dpp/dave/version.cpp | 37 + src/dpp/dave/version.h | 48 + src/dpp/discordclient.cpp | 23 +- src/dpp/discordvoiceclient.cpp | 1115 +------- src/dpp/guild.cpp | 4 +- src/dpp/httpsclient.cpp | 2 +- src/dpp/sslclient.cpp | 2 +- src/dpp/utility.cpp | 8 +- src/dpp/voice/enabled/audio_mix.cpp | 55 + src/dpp/voice/enabled/cleanup.cpp | 62 + src/dpp/voice/enabled/constructor.cpp | 91 + src/dpp/voice/enabled/courier_loop.cpp | 174 ++ src/dpp/voice/enabled/discover_ip.cpp | 206 ++ src/dpp/voice/enabled/displayable_code.cpp | 51 + src/dpp/voice/enabled/enabled.h | 110 + src/dpp/voice/enabled/handle_frame.cpp | 451 +++ src/dpp/voice/enabled/opus.cpp | 206 ++ src/dpp/voice/enabled/read_ready.cpp | 215 ++ src/dpp/voice/enabled/read_write.cpp | 74 + src/dpp/voice/enabled/thread.cpp | 87 + src/dpp/voice/enabled/voice_payload.cpp | 69 + src/dpp/voice/enabled/write_ready.cpp | 115 + src/dpp/voice/stub/stub.h | 65 + src/dpp/voice/stub/stubs.cpp | 102 + src/dpp/wsclient.cpp | 35 +- testdata/Robot.pcm | Bin 149504 -> 2104292 bytes vcpkg/ports/dpp/portfile.cmake | 2 +- vcpkg/ports/dpp/vcpkg.json | 2 +- vcpkg/versions/baseline.json | 2472 +++++++++-------- vcpkg/versions/d-/dpp.json | 5 + 160 files changed, 30045 insertions(+), 2246 deletions(-) create mode 100644 cmake/FindFilesystem.cmake create mode 100755 docpages/images/audioframe.svg create mode 100755 mlspp/CMakeLists.txt create mode 100755 mlspp/LICENSE create mode 100755 mlspp/cmake/config.cmake.in create mode 100755 mlspp/cmake/namespace.h.in create mode 100755 mlspp/include/mls/common.h create mode 100755 mlspp/include/mls/core_types.h create mode 100755 mlspp/include/mls/credential.h create mode 100755 mlspp/include/mls/crypto.h create mode 100755 mlspp/include/mls/key_schedule.h create mode 100755 mlspp/include/mls/messages.h create mode 100755 mlspp/include/mls/session.h create mode 100755 mlspp/include/mls/state.h create mode 100755 mlspp/include/mls/tree_math.h create mode 100755 mlspp/include/mls/treekem.h create mode 100755 mlspp/include/namespace.h create mode 100755 mlspp/include/version.h create mode 100755 mlspp/lib/CMakeLists.txt create mode 100755 mlspp/lib/bytes/CMakeLists.txt create mode 100755 mlspp/lib/bytes/include/bytes/bytes.h create mode 100755 mlspp/lib/bytes/include/tls/compat.h create mode 100755 mlspp/lib/bytes/include/tls/tls_syntax.h create mode 100755 mlspp/lib/bytes/src/bytes.cpp create mode 100755 mlspp/lib/hpke/CMakeLists.txt create mode 100755 mlspp/lib/hpke/include/hpke/base64.h create mode 100755 mlspp/lib/hpke/include/hpke/certificate.h create mode 100755 mlspp/lib/hpke/include/hpke/digest.h create mode 100755 mlspp/lib/hpke/include/hpke/hpke.h create mode 100755 mlspp/lib/hpke/include/hpke/random.h create mode 100755 mlspp/lib/hpke/include/hpke/signature.h create mode 100755 mlspp/lib/hpke/include/hpke/userinfo_vc.h create mode 100755 mlspp/lib/hpke/src/aead_cipher.cpp create mode 100755 mlspp/lib/hpke/src/aead_cipher.h create mode 100755 mlspp/lib/hpke/src/base64.cpp create mode 100755 mlspp/lib/hpke/src/certificate.cpp create mode 100755 mlspp/lib/hpke/src/common.cpp create mode 100755 mlspp/lib/hpke/src/common.h create mode 100755 mlspp/lib/hpke/src/dhkem.cpp create mode 100755 mlspp/lib/hpke/src/dhkem.h create mode 100755 mlspp/lib/hpke/src/digest.cpp create mode 100755 mlspp/lib/hpke/src/group.cpp create mode 100755 mlspp/lib/hpke/src/group.h create mode 100755 mlspp/lib/hpke/src/hkdf.cpp create mode 100755 mlspp/lib/hpke/src/hkdf.h create mode 100755 mlspp/lib/hpke/src/hpke.cpp create mode 100755 mlspp/lib/hpke/src/openssl_common.cpp create mode 100755 mlspp/lib/hpke/src/openssl_common.h create mode 100755 mlspp/lib/hpke/src/random.cpp create mode 100755 mlspp/lib/hpke/src/rsa.cpp create mode 100755 mlspp/lib/hpke/src/rsa.h create mode 100755 mlspp/lib/hpke/src/signature.cpp create mode 100755 mlspp/lib/hpke/src/userinfo_vc.cpp create mode 100755 mlspp/lib/mls_vectors/CMakeLists.txt create mode 100755 mlspp/lib/mls_vectors/include/mls_vectors/mls_vectors.h create mode 100755 mlspp/lib/mls_vectors/src/mls_vectors.cpp create mode 100755 mlspp/lib/tls_syntax/CMakeLists.txt create mode 100755 mlspp/lib/tls_syntax/include/tls/compat.h create mode 100755 mlspp/lib/tls_syntax/include/tls/tls_syntax.h create mode 100755 mlspp/lib/tls_syntax/src/tls_syntax.cpp create mode 100755 mlspp/src/common.cpp create mode 100755 mlspp/src/core_types.cpp create mode 100755 mlspp/src/credential.cpp create mode 100755 mlspp/src/crypto.cpp create mode 100755 mlspp/src/grease.cpp create mode 100755 mlspp/src/grease.h create mode 100755 mlspp/src/key_schedule.cpp create mode 100755 mlspp/src/messages.cpp create mode 100755 mlspp/src/session.cpp create mode 100755 mlspp/src/state.cpp create mode 100755 mlspp/src/tree_math.cpp create mode 100755 mlspp/src/treekem.cpp create mode 100644 src/davetest/dave.cpp create mode 100755 src/dpp/dave/array_view.h create mode 100755 src/dpp/dave/cipher_interface.cpp create mode 100755 src/dpp/dave/cipher_interface.h create mode 100755 src/dpp/dave/clock.h create mode 100755 src/dpp/dave/codec_utils.cpp create mode 100755 src/dpp/dave/codec_utils.h create mode 100755 src/dpp/dave/common.h create mode 100755 src/dpp/dave/cryptor_manager.cpp create mode 100755 src/dpp/dave/cryptor_manager.h create mode 100755 src/dpp/dave/decryptor.cpp create mode 100755 src/dpp/dave/decryptor.h create mode 100755 src/dpp/dave/encryptor.cpp create mode 100755 src/dpp/dave/encryptor.h create mode 100755 src/dpp/dave/frame_processors.cpp create mode 100755 src/dpp/dave/frame_processors.h create mode 100755 src/dpp/dave/key_ratchet.h create mode 100755 src/dpp/dave/leb128.cpp create mode 100755 src/dpp/dave/leb128.h create mode 100755 src/dpp/dave/mls_key_ratchet.cpp create mode 100755 src/dpp/dave/mls_key_ratchet.h create mode 100755 src/dpp/dave/openssl_aead_cipher.cpp create mode 100755 src/dpp/dave/openssl_aead_cipher.h create mode 100755 src/dpp/dave/parameters.cpp create mode 100755 src/dpp/dave/parameters.h create mode 100755 src/dpp/dave/persisted_key_pair.cpp create mode 100755 src/dpp/dave/persisted_key_pair.h create mode 100755 src/dpp/dave/persisted_key_pair_generic.cpp create mode 100755 src/dpp/dave/scope_exit.h create mode 100755 src/dpp/dave/session.cpp create mode 100755 src/dpp/dave/session.h create mode 100755 src/dpp/dave/user_credential.cpp create mode 100755 src/dpp/dave/user_credential.h create mode 100755 src/dpp/dave/util.cpp create mode 100755 src/dpp/dave/util.h create mode 100755 src/dpp/dave/version.cpp create mode 100755 src/dpp/dave/version.h create mode 100644 src/dpp/voice/enabled/audio_mix.cpp create mode 100644 src/dpp/voice/enabled/cleanup.cpp create mode 100644 src/dpp/voice/enabled/constructor.cpp create mode 100644 src/dpp/voice/enabled/courier_loop.cpp create mode 100644 src/dpp/voice/enabled/discover_ip.cpp create mode 100644 src/dpp/voice/enabled/displayable_code.cpp create mode 100644 src/dpp/voice/enabled/enabled.h create mode 100644 src/dpp/voice/enabled/handle_frame.cpp create mode 100644 src/dpp/voice/enabled/opus.cpp create mode 100644 src/dpp/voice/enabled/read_ready.cpp create mode 100644 src/dpp/voice/enabled/read_write.cpp create mode 100644 src/dpp/voice/enabled/thread.cpp create mode 100644 src/dpp/voice/enabled/voice_payload.cpp create mode 100644 src/dpp/voice/enabled/write_ready.cpp create mode 100644 src/dpp/voice/stub/stub.h create mode 100644 src/dpp/voice/stub/stubs.cpp diff --git a/.cspell.json b/.cspell.json index 14eab9cec9..e19a259067 100644 --- a/.cspell.json +++ b/.cspell.json @@ -142,7 +142,12 @@ "khanda", "oclock", "moai", - "xbps" + "xbps", + "chacha20", + "chacha", + "nullopt", + "chrono", + "ciphersuite" ], "flagWords": [ "hte" diff --git a/CMakeLists.txt b/CMakeLists.txt index 874453a74c..b12fe99ef1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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. @@ -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() \ No newline at end of file diff --git a/README.md b/README.md index cdc67777d3..b6507929ea 100644 --- a/README.md +++ b/README.md @@ -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) #### 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) diff --git a/cmake/FindFilesystem.cmake b/cmake/FindFilesystem.cmake new file mode 100644 index 0000000000..a152e52293 --- /dev/null +++ b/cmake/FindFilesystem.cmake @@ -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 ` 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 `. 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 + #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() diff --git a/docpages/advanced_reference/unit_tests.md b/docpages/advanced_reference/unit_tests.md index a4a50c9ee9..03f2e78b8b 100644 --- a/docpages/advanced_reference/unit_tests.md +++ b/docpages/advanced_reference/unit_tests.md @@ -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. diff --git a/docpages/advanced_reference/voice_model.md b/docpages/advanced_reference/voice_model.md index 10bf1d4419..ca4525d174 100644 --- a/docpages/advanced_reference/voice_model.md +++ b/docpages/advanced_reference/voice_model.md @@ -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]; @@ -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"; diff --git a/docpages/images/audioframe.svg b/docpages/images/audioframe.svg new file mode 100755 index 0000000000..302f65b0db --- /dev/null +++ b/docpages/images/audioframe.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + UDP PACKET + RTP FRAME + RTP HEADER + + OPUS AUDIO(44khz 16 bit signed stereo) + + + + + DAVE (AES 128 GCM AEAD) + SODIUM (CHACHA20 POLY1305) + 8...65535 BYTES + 1..380 FRAMES PER UDP PACKET + 76 BYTES + DISCORD AUDIO FRAME LAYOUT + + diff --git a/docpages/make_a_bot/cmake.md b/docpages/make_a_bot/cmake.md index ca215d66a2..c96d8275d0 100644 --- a/docpages/make_a_bot/cmake.md +++ b/docpages/make_a_bot/cmake.md @@ -120,7 +120,7 @@ find_package_handle_standard_args(DPP DEFAULT_MSG DPP_LIBRARIES DPP_INCLUDE_DIR) ## 4. Build the bot. -Now that we have our all our cmake stuff setup and we've got our code in place, we can initalise CMake. You'll want to go inside the `build/` directory and do `cmake ..`. +Now that we have our all our cmake stuff setup and we've got our code in place, we can initalise CMake. You'll want to go inside the `build/` directory and do `cmake ..`. Once that's completed, you'll want to head back to your up-most folder (where all the folders are for your bot) and run `cmake --build build/ -j4` (replace -j4 with however many threads you want to use). This will start compiling your bot and creating the executable. diff --git a/doxygen-awesome-css b/doxygen-awesome-css index 568f56cde6..4593c19803 160000 --- a/doxygen-awesome-css +++ b/doxygen-awesome-css @@ -1 +1 @@ -Subproject commit 568f56cde6ac78b6dfcc14acd380b2e745c301ea +Subproject commit 4593c198030b6e5019aae4d9c2eeb7497f02dbf8 diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 7a5ebfd63b..4dad2327f2 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -445,7 +445,16 @@ class DPP_EXPORT cluster { */ event_router_t on_voice_state_update; - + /** + * @brief on voice client platform event + * After a client connects, or on joining a vc, you will receive the platform type of each client. This is either desktop + * or mobile. + * + * @note Use operator() to attach a lambda to this event, and the detach method to detach the listener using the returned ID. + * The function signature for this event takes a single `const` reference of type voice_client_disconnect_t&, and returns void. + */ + event_router_t on_voice_client_platform; + /** * @brief on voice client disconnect event * diff --git a/include/dpp/discordclient.h b/include/dpp/discordclient.h index ff2f7736f7..872dbaa916 100644 --- a/include/dpp/discordclient.h +++ b/include/dpp/discordclient.h @@ -87,6 +87,12 @@ class DPP_EXPORT voiceconn { */ class discord_voice_client* voiceclient; + /** + * @brief True to enable DAVE E2EE + * @warning This is an EXPERIMENTAL feature! + */ + bool dave; + /** * @brief Construct a new voiceconn object */ @@ -97,8 +103,10 @@ class DPP_EXPORT voiceconn { * * @param o owner * @param _channel_id voice channel id + * @param enable_dave True to enable DAVE E2EE + * @warn DAVE is an EXPERIMENTAL feature! */ - voiceconn(class discord_client* o, snowflake _channel_id); + voiceconn(class discord_client* o, snowflake _channel_id, bool enable_dave); /** * @brief Destroy the voiceconn object @@ -473,9 +481,10 @@ class DPP_EXPORT discord_client : public websocket_client /** * @brief Handle JSON from the websocket. * @param buffer The entire buffer content from the websocket client + * @param opcode The type of frame, e.g. text or binary * @returns True if a frame has been handled */ - virtual bool handle_frame(const std::string &buffer); + virtual bool handle_frame(const std::string &buffer, ws_opcode opcode); /** * @brief Handle a websocket error. @@ -497,12 +506,13 @@ class DPP_EXPORT discord_client : public websocket_client * @param channel_id Channel ID of the voice channel * @param self_mute True if the bot should mute itself * @param self_deaf True if the bot should deafen itself + * @param enable_dave True to enable DAVE E2EE - EXPERIMENTAL * @return reference to self * @note This is NOT a synchronous blocking call! The bot isn't instantly ready to send or listen for audio, * as we have to wait for the connection to the voice server to be established! * e.g. wait for dpp::cluster::on_voice_ready event, and then send the audio within that event. */ - discord_client& connect_voice(snowflake guild_id, snowflake channel_id, bool self_mute = false, bool self_deaf = false); + discord_client& connect_voice(snowflake guild_id, snowflake channel_id, bool self_mute = false, bool self_deaf = false, bool enable_dave = false); /** * @brief Disconnect from the connected voice channel on a guild diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 8ed58107d8..9edeef94fa 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -48,6 +48,7 @@ #include #include #include +#include struct OpusDecoder; struct OpusEncoder; @@ -55,8 +56,28 @@ struct OpusRepacketizer; namespace dpp { +/** + * @brief Sample rate for OPUS (48khz) + */ +[[maybe_unused]] inline constexpr int32_t opus_sample_rate_hz = 48000; + +/** + * @brief Channel count for OPUS (stereo) + */ +[[maybe_unused]] inline constexpr int32_t opus_channel_count = 2; + +/** + * @brief Discord voice protocol version + */ +[[maybe_unused]] inline constexpr uint8_t voice_protocol_version = 8; + + class audio_mixer; +namespace dave::mls { + class session; +} + // !TODO: change these to constexpr and rename every occurrence across the codebase #define AUDIO_TRACK_MARKER (uint16_t)0xFFFF @@ -64,6 +85,10 @@ class audio_mixer; inline constexpr size_t send_audio_raw_max_length = 11520; +inline constexpr size_t secret_key_size = 32; + +struct dave_state; + /* * @brief For holding a moving average of the number of current voice users, for applying a smooth gain ramp. */ @@ -100,6 +125,112 @@ struct DPP_EXPORT voice_out_packet { uint64_t duration; }; +/** + * @brief Supported DAVE (Discord Audio Visual Encryption) protocol versions + */ +enum dave_version_t : uint8_t { + /** + * @brief DAVE disabled (default for now) + */ + dave_version_none = 0, + /** + * @brief DAVE enabled, version 1 (E2EE encryption on top of sodium) + */ + dave_version_1 = 1, +}; + +/** + * @brief Discord voice websocket opcode types + */ +enum voice_websocket_opcode_t : uint8_t { + voice_opcode_connection_identify = 0, + voice_opcode_connection_select_protocol = 1, + voice_opcode_connection_ready = 2, + voice_opcode_connection_heartbeat = 3, + voice_opcode_connection_description = 4, + voice_opcode_client_speaking = 5, + voice_opcode_connection_heartbeat_ack = 6, + voice_opcode_connection_resume = 7, + voice_opcode_connection_hello = 8, + voice_opcode_connection_resumed = 9, + voice_opcode_multiple_clients_connect = 11, + voice_opcode_client_connect = 12, + voice_opcode_client_disconnect = 13, + voice_opcode_media_sink = 15, + voice_client_flags = 18, + voice_client_platform = 20, + voice_client_dave_prepare_transition = 21, + voice_client_dave_execute_transition = 22, + voice_client_dave_transition_ready = 23, + voice_client_dave_prepare_epoch = 24, + voice_client_dave_mls_external_sender = 25, + voice_client_dave_mls_key_package = 26, + voice_client_dave_mls_proposals = 27, + voice_client_dave_mls_commit_message = 28, + voice_client_dave_announce_commit_transaction = 29, + voice_client_dave_mls_welcome = 30, + voice_client_dave_mls_invalid_commit_welcome = 31, +}; + +/** + * @brief DAVE E2EE Binary frame header + */ +struct dave_binary_header_t { + /** + * @brief Sequence number + */ + uint16_t seq; + + /** + * @brief Opcode type + */ + uint8_t opcode; + + /** + * @brief Data package, an opaque structure passed to the + * Discord libdave functions. + */ + std::vector package; + + /** + * @brief Fill binary header from inbound buffer + * @param buffer inbound websocket buffer + */ + dave_binary_header_t(const std::string& buffer); + + /** + * Get the data package from the packed binary frame, as a vector of uint8_t + * for use in the libdave functions + + * @return data blob + */ + [[nodiscard]] std::vector get_data() const; + + /** + * Get transition ID for process_welcome + * + * @return Transition ID + */ + [[nodiscard]] uint16_t get_transition_id() const; + +private: + /** + * @brief Transition id, only valid when the opcode is + * welcome state. Use get_transition_id() to obtain value. + */ + uint16_t transition_id; +}; + +/** + * @brief A callback for obtaining a user's privacy code. + * The privacy code is returned as the parameter to the function. + * + * This is a callback function because DAVE requires use of a very resource + * intensive SCRYPT call, which uses lots of ram and cpu and take significant + * time. + */ +using privacy_code_callback_t = std::function; + /** @brief Implements a discord voice connection. * Each discord_voice_client connects to one voice channel and derives from a websocket client. */ @@ -120,6 +251,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ std::shared_mutex queue_mutex; + /** + * @brief Our public IP address + * + * Use discord_voice_client::discover_ip() to access this value + */ + std::string external_ip; + /** * @brief Queue of outbound messages */ @@ -308,6 +446,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client * (merges frames into one packet) */ OpusRepacketizer* repacketizer; + + /** + * @brief This holds the state information for DAVE E2EE. + * it is only allocated if E2EE is active on the voice channel. + */ + std::unique_ptr mls_state; + #else /** * @brief libopus encoder @@ -319,8 +464,20 @@ class DPP_EXPORT discord_voice_client : public websocket_client * (merges frames into one packet) */ void* repacketizer; + + /** + * @brief This holds the state information for DAVE E2EE. + * it is only allocated if E2EE is active on the voice channel. + */ + std::unique_ptr mls_state{}; #endif + /** + * @brief The list of users that have E2EE potentially enabled for + * DAVE protocol. + */ + std::set dave_mls_user_list; + /** * @brief File descriptor for UDP connection */ @@ -328,10 +485,15 @@ class DPP_EXPORT discord_voice_client : public websocket_client /** * @brief Secret key for encrypting voice. - * If it has been sent, this is non-null and points to a - * sequence of exactly 32 bytes. + * If it has been sent, this contains a sequence of exactly 32 bytes + * (secret_key_size) and has_secret_key is set to true. + */ + std::array secret_key; + + /** + * @brief True if the voice client has a secret key */ - uint8_t* secret_key; + bool has_secret_key{false}; /** * @brief Sequence number of outbound audio. This is incremented @@ -339,6 +501,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ uint16_t sequence; + /** + * @brief Last received sequence from gateway. + * + * Needed for heartbeat and resume payload. + */ + int32_t receive_sequence; + /** * @brief Timestamp value used in outbound audio. Each packet * has the timestamp value which is incremented to match @@ -402,6 +571,14 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ uint8_t encode_buffer[65536]; + /** + * @brief DAVE - Discord Audio Visual Encryption + * Used for E2EE encryption. dave_protocol_none is + * the default right now. + * @warning DAVE E2EE is an EXPERIMENTAL feature! + */ + dave_version_t dave_version; + /** * @brief Send data to UDP socket immediately. * @@ -687,9 +864,11 @@ class DPP_EXPORT discord_voice_client : public websocket_client * @param _token The voice session token to use for identifying to the websocket * @param _session_id The voice session id to identify with * @param _host The voice server hostname to connect to (hostname:port format) + * @param enable_dave Enable DAVE E2EE * @throw dpp::voice_exception Sodium or Opus failed to initialise, or D++ is not compiled with voice support + * @warning DAVE E2EE is an EXPERIMENTAL feature! */ - discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host); + discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host, bool enable_dave = false); /** * @brief Destroy the discord voice client object @@ -699,10 +878,11 @@ class DPP_EXPORT discord_voice_client : public websocket_client /** * @brief Handle JSON from the websocket. * @param buffer The entire buffer content from the websocket client + * @param opcode Frame type, e.g. OP_TEXT, OP_BINARY * @return bool True if a frame has been handled * @throw dpp::exception If there was an error processing the frame, or connection to UDP socket failed */ - virtual bool handle_frame(const std::string &buffer); + virtual bool handle_frame(const std::string &buffer, ws_opcode opcode); /** * @brief Handle a websocket error. @@ -975,6 +1155,41 @@ class DPP_EXPORT discord_voice_client : public websocket_client * for a single packet from Discord's voice servers. */ std::string discover_ip(); + + /** + * @brief Returns true if end-to-end encryption is enabled + * for the active voice call (Discord Audio Visual + * Encryption, a.k.a. DAVE). + * + * @return True if end-to-end encrypted + */ + bool is_end_to_end_encrypted() const; + + /** + * @brief Returns the privacy code for the end to end encryption + * scheme ("DAVE"). if end-to-end encryption is not active, + * or is not yet established, this will return an empty + * string. + * + * @return A sequence of six five-digit integers which + * can be matched against the Discord client, in the + * privacy tab for the properties of the voice call. + */ + std::string get_privacy_code() const; + + /** + * @brief Returns the privacy code for a given user by id, + * if they are in the voice call, and enc-to-end encryption + * is enabled. + * + * @param user User ID to fetch the privacy code for + * @param callback Callback to call with the privacy code when + * the creation of the code is complete. + * @warning This call spawns a thread, as getting a user's + * privacy code is a CPU-intensive and memory-intensive operation + * which internally uses scrypt. + */ + void get_user_privacy_code(const dpp::snowflake user, privacy_code_callback_t callback) const; }; } // namespace dpp diff --git a/include/dpp/dispatcher.h b/include/dpp/dispatcher.h index 904633c5cc..151c2e8880 100644 --- a/include/dpp/dispatcher.h +++ b/include/dpp/dispatcher.h @@ -2144,6 +2144,44 @@ struct DPP_EXPORT voice_client_disconnect_t : public event_dispatch_t { snowflake user_id = {}; }; +/** + * @brief Discord voice platform types + */ +enum client_platform_t : uint8_t { + /** + * @brief Web, Desktop + */ + client_platform_desktop = 0, + /** + * @brief Mobile device + */ + client_platform_mobile = 1, +}; + +/** + * @brief voice client platform type notification event + */ +struct DPP_EXPORT voice_client_platform_t : public event_dispatch_t { + using event_dispatch_t::event_dispatch_t; + using event_dispatch_t::operator=; + + /** + * @brief voice client where user is + */ + discord_voice_client* voice_client = nullptr; + + /** + * @brief user id of user who left vc + */ + snowflake user_id = {}; + + /** + * @brief Client platform for the voice user + * Either desktop, or mobile + */ + client_platform_t platform = client_platform_desktop; +}; + /** * @brief Delete stage instance */ diff --git a/include/dpp/guild.h b/include/dpp/guild.h index 28c9bf720a..86c9393f0b 100644 --- a/include/dpp/guild.h +++ b/include/dpp/guild.h @@ -1288,12 +1288,14 @@ class DPP_EXPORT guild : public managed, public json_interface { * @param user_id User id to join * @param self_mute True if the bot should mute itself * @param self_deaf True if the bot should deafen itself + * @param dave True to enable DAVE E2EE + * @warning DAVE is EXPERIMENTAL and subject to change. * @return True if the user specified is in a vc, false if they aren't * @note This is NOT a synchronous blocking call! The bot isn't instantly ready to send or listen for audio, * as we have to wait for the connection to the voice server to be established! * e.g. wait for dpp::cluster::on_voice_ready event, and then send the audio within that event. */ - bool connect_member_voice(snowflake user_id, bool self_mute = false, bool self_deaf = false); + bool connect_member_voice(snowflake user_id, bool self_mute = false, bool self_deaf = false, bool dave = false); /** * @brief Get the banner url of the guild if it have one, otherwise returns an empty string diff --git a/include/dpp/isa/avx.h b/include/dpp/isa/avx.h index 367980bd9e..b84d90b56a 100644 --- a/include/dpp/isa/avx.h +++ b/include/dpp/isa/avx.h @@ -24,6 +24,8 @@ #include #include +#include +#include namespace dpp { diff --git a/include/dpp/isa/avx2.h b/include/dpp/isa/avx2.h index 1e02eaa935..009127932a 100644 --- a/include/dpp/isa/avx2.h +++ b/include/dpp/isa/avx2.h @@ -24,6 +24,8 @@ #include #include +#include +#include namespace dpp { diff --git a/include/dpp/isa/avx512.h b/include/dpp/isa/avx512.h index 68f3583801..e5535da742 100644 --- a/include/dpp/isa/avx512.h +++ b/include/dpp/isa/avx512.h @@ -24,6 +24,8 @@ #include #include +#include +#include namespace dpp { diff --git a/include/dpp/isa/fallback.h b/include/dpp/isa/fallback.h index 147ff51d0a..87a219f053 100644 --- a/include/dpp/isa/fallback.h +++ b/include/dpp/isa/fallback.h @@ -21,6 +21,8 @@ #pragma once #include +#include +#include namespace dpp { diff --git a/include/dpp/isa/neon.h b/include/dpp/isa/neon.h index 8ee33459f8..8d27d8b241 100644 --- a/include/dpp/isa/neon.h +++ b/include/dpp/isa/neon.h @@ -24,6 +24,8 @@ #include #include +#include +#include namespace dpp { diff --git a/include/dpp/sslclient.h b/include/dpp/sslclient.h index 8869aef420..e8e17e2c82 100644 --- a/include/dpp/sslclient.h +++ b/include/dpp/sslclient.h @@ -242,7 +242,7 @@ class DPP_EXPORT ssl_client * @param data Data to be written to the buffer. * @note The data may not be written immediately and may be written at a later time to the socket. */ - virtual void write(const std::string_view data); + void socket_write(const std::string_view data); /** * @brief Close socket connection diff --git a/include/dpp/utility.h b/include/dpp/utility.h index f78d3b5b9e..0dcb974972 100644 --- a/include/dpp/utility.h +++ b/include/dpp/utility.h @@ -736,7 +736,7 @@ uint32_t DPP_EXPORT hsl(int h, int s, int l); * @param data The start of the data to display * @param length The length of data to display */ -std::string DPP_EXPORT debug_dump(uint8_t* data, size_t length); +std::string DPP_EXPORT debug_dump(const uint8_t* data, size_t length); /** * @brief Returns the length of a UTF-8 string in codepoints. diff --git a/include/dpp/wsclient.h b/include/dpp/wsclient.h index 98b48aa3de..ee476c14f9 100644 --- a/include/dpp/wsclient.h +++ b/include/dpp/wsclient.h @@ -91,7 +91,12 @@ enum ws_opcode : uint8_t { /** * @brief Low level pong. */ - OP_PONG = 0x0a + OP_PONG = 0x0a, + + /** + * @brief Automatic selection of type + */ + OP_AUTO = 0xff, }; /** @@ -188,8 +193,10 @@ class DPP_EXPORT websocket_client : public ssl_client { /** * @brief Write to websocket. Encapsulates data in frames if the status is CONNECTED. * @param data The data to send. + * @param _opcode The opcode of the data to send, either binary or text. The default + * is to use the socket's opcode as set in the constructor. */ - virtual void write(const std::string_view data); + virtual void write(const std::string_view data, ws_opcode _opcode = OP_AUTO); /** * @brief Processes incoming frames from the SSL socket input buffer. @@ -206,9 +213,10 @@ class DPP_EXPORT websocket_client : public ssl_client { * @brief Receives raw frame content only without headers * * @param buffer The buffer contents + * @param opcode Frame type, e.g. OP_TEXT, OP_BINARY * @return True if the frame was successfully handled. False if no valid frame is in the buffer. */ - virtual bool handle_frame(const std::string& buffer); + virtual bool handle_frame(const std::string& buffer, ws_opcode opcode); /** * @brief Called upon error frame. diff --git a/library-vcpkg/CMakeLists.txt b/library-vcpkg/CMakeLists.txt index dded1b52a5..0d7d0ac995 100644 --- a/library-vcpkg/CMakeLists.txt +++ b/library-vcpkg/CMakeLists.txt @@ -1,4 +1,29 @@ -file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") +# +# D++ (DPP), The Lightweight C++ Discord Library +# +# Copyright 2021 Craig Edwards +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +add_compile_definitions(HAVE_VOICE) + +if (HAVE_VOICE) + file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/enabled/*.cpp" "${DPP_ROOT_PATH}/dpp/dave/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") +else() + file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/stub/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") +endif() + set(LIB_NAME "${PROJECT_NAME}") @@ -31,6 +56,8 @@ if(WIN32) add_compile_definitions(WIN32_LEAN_AND_MEAN) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE) + # Fake an ssl version number to satisfy MLSPP + set(OPENSSL_VERSION "1.1.1f") endif() target_compile_options( @@ -40,8 +67,8 @@ target_compile_options( PRIVATE "$<$:$<$:/sdl;/Od;/DEBUG;/MP;/DFD_SETSIZE=1024>>" "$<$:$<$:/O2;/Oi;/Oy;/GL;/Gy;/sdl;/MP;/DFD_SETSIZE=1024>>" - "$<$:$<$:-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" - "$<$:$<$:-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" + "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" + "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" "${AVX_FLAG}" ) @@ -60,6 +87,13 @@ target_include_directories( "$" ) +if (HAVE_VOICE) + add_subdirectory("${DPP_ROOT_PATH}/mlspp" "mlspp") + include_directories("${DPP_ROOT_PATH}/mlspp/include") + include_directories("${DPP_ROOT_PATH}/mlspp/lib/bytes/include") + include_directories("${DPP_ROOT_PATH}/mlspp/lib/hpke/include") +endif() + set_target_properties( "${LIB_NAME}" PROPERTIES OUTPUT_NAME "dpp" @@ -71,8 +105,6 @@ target_link_options( "$<$:$<$:/DEBUG>>" ) -add_compile_definitions(HAVE_VOICE) - find_package(nlohmann_json CONFIG REQUIRED) find_package(OpenSSL REQUIRED) find_package(Opus CONFIG REQUIRED) @@ -90,6 +122,18 @@ target_link_libraries( $<$:Threads::Threads> ) +if (HAVE_VOICE) + # Private statically linked dependencies + target_link_libraries( + ${LIB_NAME} PRIVATE + mlspp + mls_vectors + bytes + tls_syntax + hpke + ) +endif() + set(CONFIG_FILE_NAME "${PROJECT_NAME}Config.cmake") set(EXPORTED_TARGETS_NAME "${PROJECT_NAME}Targets") set(EXPORTED_TARGETS_FILE_NAME "${EXPORTED_TARGETS_NAME}.cmake") diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index bc61c77723..5d328f295c 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -1,3 +1,20 @@ +# +# D++ (DPP), The Lightweight C++ Discord Library +# +# Copyright 2021 Craig Edwards +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Check for various C functions check_cxx_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL) check_cxx_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) @@ -32,6 +49,8 @@ add_compile_definitions(AVX_TYPE=${AVX_TYPE}) add_compile_options(${AVX_FLAG}) if(WIN32 AND NOT MINGW) + # Fake an ssl version number to satisfy MLSPP + set(OPENSSL_VERSION "1.1.1f") if (NOT WINDOWS_32_BIT) message("-- Building for windows with precompiled packaged dependencies") #set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) @@ -197,7 +216,7 @@ if(MSVC) endif() string(REGEX REPLACE "/W[1|2|3|4]" "/W3" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-private-field -Wno-psabi -Wempty-body -Wignored-qualifiers -Wimplicit-fallthrough -Wmissing-field-initializers -Wsign-compare -Wtype-limits -Wuninitialized -Wshift-negative-value -pthread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-unused-private-field -Wno-psabi -Wempty-body -Wignored-qualifiers -Wimplicit-fallthrough -Wmissing-field-initializers -Wsign-compare -Wtype-limits -Wuninitialized -Wshift-negative-value -pthread") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") if (NOT MINGW) @@ -209,11 +228,22 @@ set(modules_dir "../src") file(GLOB subdirlist ${modules_dir}/dpp) +if (HAVE_VOICE) + add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../mlspp" "mlspp") + include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../mlspp/include") + include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../mlspp/lib/bytes/include") + include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../mlspp/lib/hpke/include") +endif() + foreach (fullmodname ${subdirlist}) get_filename_component(modname ${fullmodname} NAME) set (modsrc "") - - file(GLOB modsrc "${modules_dir}/dpp/*.cpp" "${modules_dir}/dpp/events/*.cpp" "${modules_dir}/dpp/cluster/*.cpp" "${modules_dir}/dpp/*.rc") + + if (HAVE_VOICE) + file(GLOB modsrc "${modules_dir}/dpp/*.cpp" "${modules_dir}/dpp/voice/enabled/*.cpp" "${modules_dir}/dpp/dave/*.cpp" "${modules_dir}/dpp/events/*.cpp" "${modules_dir}/dpp/cluster/*.cpp" "${modules_dir}/dpp/*.rc") + else() + file(GLOB modsrc "${modules_dir}/dpp/*.cpp" "${modules_dir}/dpp/voice/stub/*.cpp" "${modules_dir}/dpp/events/*.cpp" "${modules_dir}/dpp/cluster/*.cpp" "${modules_dir}/dpp/*.rc") + endif() if(BUILD_SHARED_LIBS) add_library(${modname} SHARED ${modsrc}) @@ -241,6 +271,7 @@ foreach (fullmodname ${subdirlist}) endif() if (WIN32 AND NOT MINGW) + if (NOT WINDOWS_32_BIT) target_link_libraries(${modname} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libssl.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libcrypto.lib" @@ -262,6 +293,17 @@ foreach (fullmodname ${subdirlist}) endif () endif() + if (HAVE_VOICE) + # Private statically linked dependencies + target_link_libraries(${modname} PRIVATE + mlspp + mls_vectors + bytes + tls_syntax + hpke + ) + endif() + if (HAVE_VOICE) target_link_libraries(${modname} PUBLIC ${sodium_LIBRARY_RELEASE} ${OPUS_LIBRARIES}) @@ -269,6 +311,8 @@ foreach (fullmodname ${subdirlist}) endif() endforeach() + + target_compile_features(dpp PUBLIC cxx_std_17) target_compile_features(dpp PRIVATE cxx_constexpr) target_compile_features(dpp PRIVATE cxx_auto_type) diff --git a/mlspp/CMakeLists.txt b/mlspp/CMakeLists.txt new file mode 100755 index 0000000000..d019e83f39 --- /dev/null +++ b/mlspp/CMakeLists.txt @@ -0,0 +1,117 @@ +cmake_minimum_required(VERSION 3.13) + +project(mlspp + VERSION 0.1 + LANGUAGES CXX +) + +option(TESTING "Build tests" OFF) +option(CLANG_TIDY "Perform linting with clang-tidy" OFF) +option(SANITIZERS "Enable sanitizers" OFF) +option(MLS_NAMESPACE_SUFFIX "Namespace Suffix for CXX and CMake Export") +option(DISABLE_GREASE "Disables the inclusion of MLS protocol recommended GREASE values" ON) +option(REQUIRE_BORINGSSL "Require BoringSSL instead of OpenSSL" OFF) + +if(MLS_NAMESPACE_SUFFIX) + set(MLS_CXX_NAMESPACE "mls_${MLS_NAMESPACE_SUFFIX}" CACHE STRING "Top-level Namespace for CXX") + set(MLS_EXPORT_NAMESPACE "MLSPP${MLS_NAMESPACE_SUFFIX}" CACHE STRING "Namespace for CMake Export") +else() + set(MLS_CXX_NAMESPACE "../include/dpp/mlspp/mls" CACHE STRING "Top-level Namespace for CXX") + set(MLS_EXPORT_NAMESPACE "MLSPP" CACHE STRING "Namespace for CMake Export") +endif() +message(STATUS "CXX Namespace: ${MLS_CXX_NAMESPACE}") +message(STATUS "CMake Export Namespace: ${MLS_EXPORT_NAMESPACE}") + + +### +### Global Config +### +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +configure_file( + "cmake/namespace.h.in" + "${CMAKE_CURRENT_SOURCE_DIR}/include/namespace.h" + @ONLY +) + +include(CheckCXXCompilerFlag) +include(CMakePackageConfigHelpers) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_compile_options(-Wall) +elseif(MSVC) + add_compile_options(/W2) + add_definitions(-DWINDOWS) + + # MSVC helpfully recommends safer equivalents for things like + # getenv, but they are not portable. + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +if("$ENV{MACOSX_DEPLOYMENT_TARGET}" STREQUAL "10.11") + add_compile_options(-DVARIANT_COMPAT) +endif() + +add_compile_options(-DDISABLE_GREASE) + +### +### Dependencies +### + +# Configure vcpkg to only build release libraries +set(VCPKG_BUILD_TYPE release) + +if (${OPENSSL_VERSION} VERSION_GREATER_EQUAL 3) + add_compile_definitions(WITH_OPENSSL3) +elseif(${OPENSSL_VERSION} VERSION_LESS 1.1.1) + message(FATAL_ERROR "OpenSSL 1.1.1 or greater is required") +endif() +message(STATUS "OpenSSL Found: ${OPENSSL_VERSION}") +message(STATUS "OpenSSL Include: ${OPENSSL_INCLUDE_DIR}") +message(STATUS "OpenSSL Libraries: ${OPENSSL_LIBRARIES}") + +# Internal libraries +add_subdirectory(lib) + +### +### Library Config +### + +set(LIB_NAME "${PROJECT_NAME}") + +file(GLOB_RECURSE LIB_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +add_library(${LIB_NAME} STATIC ${LIB_HEADERS} ${LIB_SOURCES}) +add_dependencies(${LIB_NAME} bytes tls_syntax hpke) +target_link_libraries(${LIB_NAME} bytes tls_syntax hpke) +target_include_directories(${LIB_NAME} + PUBLIC + $ + $ + PRIVATE + ${OPENSSL_INCLUDE_DIR} +) + +### +### Exports +### +set(CMAKE_EXPORT_PACKAGE_REGISTRY ON) +export(PACKAGE ${MLS_EXPORT_NAMESPACE}) + +configure_package_config_file(cmake/config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${MLS_EXPORT_NAMESPACE}Config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/${MLS_EXPORT_NAMESPACE} + NO_SET_AND_CHECK_MACRO) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${MLS_EXPORT_NAMESPACE}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib/bytes/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib/hpke/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib/mls_vectors/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/lib/tls_syntax/include") diff --git a/mlspp/LICENSE b/mlspp/LICENSE new file mode 100755 index 0000000000..044f922aa7 --- /dev/null +++ b/mlspp/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2018, Cisco Systems +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mlspp/cmake/config.cmake.in b/mlspp/cmake/config.cmake.in new file mode 100755 index 0000000000..82145af779 --- /dev/null +++ b/mlspp/cmake/config.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include(${CMAKE_CURRENT_LIST_DIR}/@MLS_EXPORT_NAMESPACE@Targets.cmake) +check_required_components(mlspp) diff --git a/mlspp/cmake/namespace.h.in b/mlspp/cmake/namespace.h.in new file mode 100755 index 0000000000..79dfad2cf5 --- /dev/null +++ b/mlspp/cmake/namespace.h.in @@ -0,0 +1,4 @@ +#pragma once + +// Configurable top-level MLS namespace +#define MLS_NAMESPACE @MLS_CXX_NAMESPACE@ diff --git a/mlspp/include/mls/common.h b/mlspp/include/mls/common.h new file mode 100755 index 0000000000..a32f9ef730 --- /dev/null +++ b/mlspp/include/mls/common.h @@ -0,0 +1,274 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals::string_literals; + +// Expose the bytes library globally +#include +using namespace mlspp::bytes_ns; + +// Expose the compatibility library globally +#include +namespace var = mlspp::tls::var; +namespace opt = mlspp::tls::opt; + +namespace mlspp { + +// Make variant equality work in the same way as optional equality, with +// automatic unwrapping. In other words +// +// v == T(x) <=> hold_alternative(v) && get(v) == x +// +// For consistency, we also define symmetric and negated version. In this +// house, we obey the symmetric law of equivalence relations! +template +bool +operator==(const var::variant& v, const T& t) +{ + return var::visit( + [&](const auto& arg) { + using U = std::decay_t; + if constexpr (std::is_same_v) { + return arg == t; + } else { + return false; + } + }, + v); +} + +template +bool +operator==(const T& t, const var::variant& v) +{ + return v == t; +} + +template +bool +operator!=(const var::variant& v, const T& t) +{ + return !(v == t); +} + +template +bool +operator!=(const T& t, const var::variant& v) +{ + return !(v == t); +} + +using epoch_t = uint64_t; + +/// +/// Get the current system clock time in the format MLS expects +/// + +uint64_t +seconds_since_epoch(); + +/// +/// Easy construction of overloaded lambdas +/// + +template +struct overloaded : Ts... +{ + using Ts::operator()...; + + // XXX(RLB) MSVC has a bug where it incorrectly computes the size of this + // type. Microsoft claims they have fixed it in the latest MSVC, and GitHub + // claims they are running a version with the fix. But in practice, we still + // hit it. Including this dummy variable is a work-around. + // + // https://developercommunity.visualstudio.com/t/runtime-stack-corruption-using-stdvisit/346200 + int dummy = 0; +}; + +// clang-format off +// XXX(RLB): For some reason, different versions of clang-format disagree on how +// this should be formatted. Probably because it's new syntax with C++17? +// Exempting it from clang-format for now. +template overloaded(Ts...) -> overloaded; +// clang-format on + +/// +/// Auto-generate equality and inequality operators for TLS-serializable things +/// + +template +inline typename std::enable_if::type +operator==(const T& lhs, const T& rhs) +{ + return lhs._tls_fields_w() == rhs._tls_fields_w(); +} + +template +inline typename std::enable_if::type +operator!=(const T& lhs, const T& rhs) +{ + return lhs._tls_fields_w() != rhs._tls_fields_w(); +} + +/// +/// Error types +/// + +// The `using parent = X` / `using parent::parent` construction here +// imports the constructors of the parent. + +class NotImplementedError : public std::exception +{ +public: + using parent = std::exception; + using parent::parent; +}; + +class ProtocolError : public std::runtime_error +{ +public: + using parent = std::runtime_error; + using parent::parent; +}; + +class IncompatibleNodesError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class InvalidParameterError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class InvalidPathError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class InvalidIndexError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class InvalidMessageTypeError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class MissingNodeError : public std::out_of_range +{ +public: + using parent = std::out_of_range; + using parent::parent; +}; + +class MissingStateError : public std::out_of_range +{ +public: + using parent = std::out_of_range; + using parent::parent; +}; + +// A slightly more elegant way to silence -Werror=unused-variable +template +void +silence_unused(const T& val) +{ + (void)val; +} + +namespace stdx { + +// XXX(RLB) This method takes any container in, but always puts the resuls in +// std::vector. The output could be made generic with a Rust-like syntax, +// defining a PendingTransform object that caches the inputs, with a template +// `collect()` method that puts them in an output container. Which makes the +// calling syntax as follows: +// +// auto out = stdx::transform(in, f).collect(); +// +// (You always need the explicit specialization, even if assigning it to an +// explicitly typed variable, because C++ won't infer return types.) +// +// Given that the above syntax is pretty chatty, and we never need anything +// other than vectors here anyway, I have left this as-is. +template +std::vector +transform(const Container& c, const UnaryOperation& op) +{ + auto out = std::vector{}; + auto ins = std::inserter(out, out.begin()); + std::transform(c.begin(), c.end(), ins, op); + return out; +} + +template +bool +any_of(const Container& c, const UnaryPredicate& pred) +{ + return std::any_of(c.begin(), c.end(), pred); +} + +template +bool +all_of(const Container& c, const UnaryPredicate& pred) +{ + return std::all_of(c.begin(), c.end(), pred); +} + +template +auto +count_if(const Container& c, const UnaryPredicate& pred) +{ + return std::count_if(c.begin(), c.end(), pred); +} + +template +bool +contains(const Container& c, const Value& val) +{ + return std::find(c.begin(), c.end(), val) != c.end(); +} + +template +auto +find_if(Container& c, const UnaryPredicate& pred) +{ + return std::find_if(c.begin(), c.end(), pred); +} + +template +auto +find_if(const Container& c, const UnaryPredicate& pred) +{ + return std::find_if(c.begin(), c.end(), pred); +} + +template +auto +upper_bound(const Container& c, const Value& val) +{ + return std::upper_bound(c.begin(), c.end(), val); +} + +} // namespace stdx + +} // namespace mlspp diff --git a/mlspp/include/mls/core_types.h b/mlspp/include/mls/core_types.h new file mode 100755 index 0000000000..6c591c0623 --- /dev/null +++ b/mlspp/include/mls/core_types.h @@ -0,0 +1,380 @@ +#pragma once + +#include "mls/credential.h" +#include "mls/crypto.h" +#include "mls/tree_math.h" + +namespace mlspp { + +// enum { +// reserved(0), +// mls10(1), +// (255) +// } ProtocolVersion; +enum class ProtocolVersion : uint16_t +{ + mls10 = 0x01, +}; + +extern const std::array all_supported_versions; + +// struct { +// ExtensionType extension_type; +// opaque extension_data; +// } Extension; +struct Extension +{ + using Type = uint16_t; + + Type type; + bytes data; + + TLS_SERIALIZABLE(type, data) +}; + +struct ExtensionType +{ + static constexpr Extension::Type application_id = 1; + static constexpr Extension::Type ratchet_tree = 2; + static constexpr Extension::Type required_capabilities = 3; + static constexpr Extension::Type external_pub = 4; + static constexpr Extension::Type external_senders = 5; + + // XXX(RLB) There is no IANA-registered type for this extension yet, so we use + // a value from the vendor-specific space + static constexpr Extension::Type sframe_parameters = 0xff02; +}; + +struct ExtensionList +{ + std::vector extensions; + + // XXX(RLB) It would be good if this maintained extensions in order. It might + // be possible to do this automatically by changing the storage to a + // map and extending the TLS code to marshal that type. + template + inline void add(const T& obj) + { + auto data = tls::marshal(obj); + add(T::type, std::move(data)); + } + + void add(Extension::Type type, bytes data); + + template + std::optional find() const + { + for (const auto& ext : extensions) { + if (ext.type == T::type) { + return tls::get(ext.data); + } + } + + return std::nullopt; + } + + bool has(uint16_t type) const; + + TLS_SERIALIZABLE(extensions) +}; + +// enum { +// reserved(0), +// key_package(1), +// update(2), +// commit(3), +// (255) +// } LeafNodeSource; +enum struct LeafNodeSource : uint8_t +{ + key_package = 1, + update = 2, + commit = 3, +}; + +// struct { +// ProtocolVersion versions; +// CipherSuite ciphersuites; +// ExtensionType extensions; +// ProposalType proposals; +// CredentialType credentials; +// } Capabilities; +struct Capabilities +{ + std::vector versions; + std::vector cipher_suites; + std::vector extensions; + std::vector proposals; + std::vector credentials; + + static Capabilities create_default(); + bool extensions_supported(const std::vector& required) const; + bool proposals_supported(const std::vector& required) const; + bool credential_supported(const Credential& credential) const; + + template + bool credentials_supported(const Container& required) const + { + return stdx::all_of(required, [&](CredentialType type) { + return stdx::contains(credentials, type); + }); + } + + TLS_SERIALIZABLE(versions, cipher_suites, extensions, proposals, credentials) +}; + +// struct { +// uint64 not_before; +// uint64 not_after; +// } Lifetime; +struct Lifetime +{ + uint64_t not_before; + uint64_t not_after; + + static Lifetime create_default(); + + TLS_SERIALIZABLE(not_before, not_after) +}; + +// struct { +// HPKEPublicKey encryption_key; +// SignaturePublicKey signature_key; +// Credential credential; +// Capabilities capabilities; +// +// LeafNodeSource leaf_node_source; +// select (leaf_node_source) { +// case add: +// Lifetime lifetime; +// +// case update: +// struct {} +// +// case commit: +// opaque parent_hash; +// } +// +// Extension extensions; +// // SignWithLabel(., "LeafNodeTBS", LeafNodeTBS) +// opaque signature; +// } LeafNode; +struct Empty +{ + TLS_SERIALIZABLE() +}; + +struct ParentHash +{ + bytes parent_hash; + TLS_SERIALIZABLE(parent_hash); +}; + +struct LeafNodeOptions +{ + std::optional credential; + std::optional capabilities; + std::optional extensions; +}; + +// TODO Move this to treekem.h +struct LeafNode +{ + HPKEPublicKey encryption_key; + SignaturePublicKey signature_key; + Credential credential; + Capabilities capabilities; + + var::variant content; + + ExtensionList extensions; + bytes signature; + + LeafNode() = default; + LeafNode(const LeafNode&) = default; + LeafNode(LeafNode&&) = default; + LeafNode& operator=(const LeafNode&) = default; + LeafNode& operator=(LeafNode&&) = default; + + LeafNode(CipherSuite cipher_suite, + HPKEPublicKey encryption_key_in, + SignaturePublicKey signature_key_in, + Credential credential_in, + Capabilities capabilities_in, + Lifetime lifetime_in, + ExtensionList extensions_in, + const SignaturePrivateKey& sig_priv); + + LeafNode for_update(CipherSuite cipher_suite, + const bytes& group_id, + LeafIndex leaf_index, + HPKEPublicKey encryption_key, + const LeafNodeOptions& opts, + const SignaturePrivateKey& sig_priv_in) const; + + LeafNode for_commit(CipherSuite cipher_suite, + const bytes& group_id, + LeafIndex leaf_index, + HPKEPublicKey encryption_key, + const bytes& parent_hash, + const LeafNodeOptions& opts, + const SignaturePrivateKey& sig_priv_in) const; + + void set_capabilities(Capabilities capabilities_in); + + LeafNodeSource source() const; + + struct MemberBinding + { + bytes group_id; + LeafIndex leaf_index; + TLS_SERIALIZABLE(group_id, leaf_index); + }; + + void sign(CipherSuite cipher_suite, + const SignaturePrivateKey& sig_priv, + const std::optional& binding); + bool verify(CipherSuite cipher_suite, + const std::optional& binding) const; + + bool verify_expiry(uint64_t now) const; + bool verify_extension_support(const ExtensionList& ext_list) const; + + TLS_SERIALIZABLE(encryption_key, + signature_key, + credential, + capabilities, + content, + extensions, + signature) + TLS_TRAITS(tls::pass, + tls::pass, + tls::pass, + tls::pass, + tls::variant, + tls::pass, + tls::pass) + +private: + LeafNode clone_with_options(HPKEPublicKey encryption_key, + const LeafNodeOptions& opts) const; + bytes to_be_signed(const std::optional& binding) const; +}; + +// Concrete extension types +struct RequiredCapabilitiesExtension +{ + std::vector extensions; + std::vector proposals; + + static const Extension::Type type; + TLS_SERIALIZABLE(extensions, proposals) +}; + +struct ApplicationIDExtension +{ + bytes id; + + static const Extension::Type type; + TLS_SERIALIZABLE(id) +}; + +/// +/// NodeType, ParentNode, and KeyPackage +/// + +// TODO move this to treekem.h +struct ParentNode +{ + HPKEPublicKey public_key; + bytes parent_hash; + std::vector unmerged_leaves; + + bytes hash(CipherSuite suite) const; + + TLS_SERIALIZABLE(public_key, parent_hash, unmerged_leaves) +}; + +// TODO Move this to messages.h +// struct { +// ProtocolVersion version; +// CipherSuite cipher_suite; +// HPKEPublicKey init_key; +// LeafNode leaf_node; +// Extension extensions; +// // SignWithLabel(., "KeyPackageTBS", KeyPackageTBS) +// opaque signature; +// } KeyPackage; +struct KeyPackage +{ + ProtocolVersion version; + CipherSuite cipher_suite; + HPKEPublicKey init_key; + LeafNode leaf_node; + ExtensionList extensions; + bytes signature; + + KeyPackage(); + KeyPackage(CipherSuite suite_in, + HPKEPublicKey init_key_in, + LeafNode leaf_node_in, + ExtensionList extensions_in, + const SignaturePrivateKey& sig_priv_in); + + KeyPackageRef ref() const; + + void sign(const SignaturePrivateKey& sig_priv); + bool verify() const; + + TLS_SERIALIZABLE(version, + cipher_suite, + init_key, + leaf_node, + extensions, + signature) + +private: + bytes to_be_signed() const; +}; + +/// +/// UpdatePath +/// + +// struct { +// HPKEPublicKey public_key; +// HPKECiphertext encrypted_path_secret; +// } UpdatePathNode; +struct UpdatePathNode +{ + HPKEPublicKey public_key; + std::vector encrypted_path_secret; + + TLS_SERIALIZABLE(public_key, encrypted_path_secret) +}; + +// struct { +// LeafNode leaf_node; +// UpdatePathNode nodes; +// } UpdatePath; +struct UpdatePath +{ + LeafNode leaf_node; + std::vector nodes; + + TLS_SERIALIZABLE(leaf_node, nodes) +}; + +} // namespace mlspp + +namespace mlspp::tls { + +TLS_VARIANT_MAP(mlspp::LeafNodeSource, + mlspp::Lifetime, + key_package) +TLS_VARIANT_MAP(mlspp::LeafNodeSource, mlspp::Empty, update) +TLS_VARIANT_MAP(mlspp::LeafNodeSource, + mlspp::ParentHash, + commit) + +} // namespace mlspp::tls diff --git a/mlspp/include/mls/credential.h b/mlspp/include/mls/credential.h new file mode 100755 index 0000000000..bcf77a36cc --- /dev/null +++ b/mlspp/include/mls/credential.h @@ -0,0 +1,228 @@ +#pragma once + +#include +#include + +namespace mlspp { + +namespace hpke { +struct UserInfoVC; +} + +// struct { +// opaque identity<0..2^16-1>; +// SignaturePublicKey public_key; +// } BasicCredential; +struct BasicCredential +{ + BasicCredential() {} + + BasicCredential(bytes identity_in) + : identity(std::move(identity_in)) + { + } + + bytes identity; + + TLS_SERIALIZABLE(identity) +}; + +struct X509Credential +{ + struct CertData + { + bytes data; + + TLS_SERIALIZABLE(data) + }; + + X509Credential() = default; + explicit X509Credential(const std::vector& der_chain_in); + + SignatureScheme signature_scheme() const; + SignaturePublicKey public_key() const; + bool valid_for(const SignaturePublicKey& pub) const; + + // TODO(rlb) This should be const or exposed via a method + std::vector der_chain; + +private: + SignaturePublicKey _public_key; + SignatureScheme _signature_scheme; +}; + +tls::ostream& +operator<<(tls::ostream& str, const X509Credential& obj); + +tls::istream& +operator>>(tls::istream& str, X509Credential& obj); + +struct UserInfoVCCredential +{ + UserInfoVCCredential() = default; + explicit UserInfoVCCredential(std::string userinfo_vc_jwt_in); + + std::string userinfo_vc_jwt; + + bool valid_for(const SignaturePublicKey& pub) const; + bool valid_from(const PublicJWK& pub) const; + + friend tls::ostream operator<<(tls::ostream& str, + const UserInfoVCCredential& obj); + friend tls::istream operator>>(tls::istream& str, UserInfoVCCredential& obj); + friend bool operator==(const UserInfoVCCredential& lhs, + const UserInfoVCCredential& rhs); + friend bool operator!=(const UserInfoVCCredential& lhs, + const UserInfoVCCredential& rhs); + +private: + std::shared_ptr _vc; +}; + +bool +operator==(const X509Credential& lhs, const X509Credential& rhs); + +enum struct CredentialType : uint16_t +{ + reserved = 0, + basic = 1, + x509 = 2, + + userinfo_vc_draft_00 = 0xFE00, + multi_draft_00 = 0xFF00, + + // GREASE values, included here mainly so that debugger output looks nice + GREASE_0 = 0x0A0A, + GREASE_1 = 0x1A1A, + GREASE_2 = 0x2A2A, + GREASE_3 = 0x3A3A, + GREASE_4 = 0x4A4A, + GREASE_5 = 0x5A5A, + GREASE_6 = 0x6A6A, + GREASE_7 = 0x7A7A, + GREASE_8 = 0x8A8A, + GREASE_9 = 0x9A9A, + GREASE_A = 0xAAAA, + GREASE_B = 0xBABA, + GREASE_C = 0xCACA, + GREASE_D = 0xDADA, + GREASE_E = 0xEAEA, +}; + +// struct { +// Credential credential; +// SignaturePublicKey credential_key; +// opaque signature; +// } CredentialBinding +// +// struct { +// CredentialBinding bindings; +// } MultiCredential; +struct CredentialBinding; +struct CredentialBindingInput; + +struct MultiCredential +{ + MultiCredential() = default; + MultiCredential(const std::vector& binding_inputs, + const SignaturePublicKey& signature_key); + + std::vector bindings; + + bool valid_for(const SignaturePublicKey& pub) const; + + TLS_SERIALIZABLE(bindings) +}; + +// struct { +// CredentialType credential_type; +// select (credential_type) { +// case basic: +// BasicCredential; +// +// case x509: +// opaque cert_data<1..2^24-1>; +// }; +// } Credential; +struct Credential +{ + Credential() = default; + + CredentialType type() const; + + template + const T& get() const + { + return var::get(_cred); + } + + static Credential basic(const bytes& identity); + static Credential x509(const std::vector& der_chain); + static Credential userinfo_vc(const std::string& userinfo_vc_jwt); + static Credential multi( + const std::vector& binding_inputs, + const SignaturePublicKey& signature_key); + + bool valid_for(const SignaturePublicKey& pub) const; + + TLS_SERIALIZABLE(_cred) + TLS_TRAITS(tls::variant) + +private: + using SpecificCredential = var::variant; + + Credential(SpecificCredential specific); + SpecificCredential _cred; +}; + +// XXX(RLB): This struct needs to appear below Credential so that all types are +// concrete at the appropriate points. +struct CredentialBindingInput +{ + CipherSuite cipher_suite; + Credential credential; + const SignaturePrivateKey& credential_priv; +}; + +struct CredentialBinding +{ + CipherSuite cipher_suite; + Credential credential; + SignaturePublicKey credential_key; + bytes signature; + + CredentialBinding() = default; + CredentialBinding(CipherSuite suite_in, + Credential credential_in, + const SignaturePrivateKey& credential_priv, + const SignaturePublicKey& signature_key); + + bool valid_for(const SignaturePublicKey& signature_key) const; + + TLS_SERIALIZABLE(cipher_suite, credential, credential_key, signature) + +private: + bytes to_be_signed(const SignaturePublicKey& signature_key) const; +}; + +} // namespace mlspp + +namespace mlspp::tls { + +TLS_VARIANT_MAP(mlspp::CredentialType, + mlspp::BasicCredential, + basic) +TLS_VARIANT_MAP(mlspp::CredentialType, + mlspp::X509Credential, + x509) +TLS_VARIANT_MAP(mlspp::CredentialType, + mlspp::UserInfoVCCredential, + userinfo_vc_draft_00) +TLS_VARIANT_MAP(mlspp::CredentialType, + mlspp::MultiCredential, + multi_draft_00) + +} // namespace mlspp::tls diff --git a/mlspp/include/mls/crypto.h b/mlspp/include/mls/crypto.h new file mode 100755 index 0000000000..f9924de02d --- /dev/null +++ b/mlspp/include/mls/crypto.h @@ -0,0 +1,266 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace mlspp { + +/// Signature Code points, borrowed from RFC 8446 +enum struct SignatureScheme : uint16_t +{ + ecdsa_secp256r1_sha256 = 0x0403, + ecdsa_secp384r1_sha384 = 0x0805, + ecdsa_secp521r1_sha512 = 0x0603, + ed25519 = 0x0807, + ed448 = 0x0808, + rsa_pkcs1_sha256 = 0x0401, +}; + +SignatureScheme +tls_signature_scheme(hpke::Signature::ID id); + +/// Cipher suites + +struct KeyAndNonce +{ + bytes key; + bytes nonce; +}; + +// opaque HashReference; +// HashReference KeyPackageRef; +// HashReference ProposalRef; +using HashReference = bytes; +using KeyPackageRef = HashReference; +using ProposalRef = HashReference; + +struct CipherSuite +{ + enum struct ID : uint16_t + { + unknown = 0x0000, + X25519_AES128GCM_SHA256_Ed25519 = 0x0001, + P256_AES128GCM_SHA256_P256 = 0x0002, + X25519_CHACHA20POLY1305_SHA256_Ed25519 = 0x0003, + X448_AES256GCM_SHA512_Ed448 = 0x0004, + P521_AES256GCM_SHA512_P521 = 0x0005, + X448_CHACHA20POLY1305_SHA512_Ed448 = 0x0006, + P384_AES256GCM_SHA384_P384 = 0x0007, + + // GREASE values, included here mainly so that debugger output looks nice + GREASE_0 = 0x0A0A, + GREASE_1 = 0x1A1A, + GREASE_2 = 0x2A2A, + GREASE_3 = 0x3A3A, + GREASE_4 = 0x4A4A, + GREASE_5 = 0x5A5A, + GREASE_6 = 0x6A6A, + GREASE_7 = 0x7A7A, + GREASE_8 = 0x8A8A, + GREASE_9 = 0x9A9A, + GREASE_A = 0xAAAA, + GREASE_B = 0xBABA, + GREASE_C = 0xCACA, + GREASE_D = 0xDADA, + GREASE_E = 0xEAEA, + }; + + CipherSuite(); + CipherSuite(ID id_in); + + ID cipher_suite() const { return id; } + SignatureScheme signature_scheme() const; + + size_t secret_size() const { return get().digest.hash_size; } + size_t key_size() const { return get().hpke.aead.key_size; } + size_t nonce_size() const { return get().hpke.aead.nonce_size; } + + bytes zero() const { return bytes(secret_size(), 0); } + const hpke::HPKE& hpke() const { return get().hpke; } + const hpke::Digest& digest() const { return get().digest; } + const hpke::Signature& sig() const { return get().sig; } + + bytes expand_with_label(const bytes& secret, + const std::string& label, + const bytes& context, + size_t length) const; + bytes derive_secret(const bytes& secret, const std::string& label) const; + bytes derive_tree_secret(const bytes& secret, + const std::string& label, + uint32_t generation, + size_t length) const; + + template + bytes ref(const T& value) const + { + return raw_ref(reference_label(), tls::marshal(value)); + } + + bytes raw_ref(const bytes& label, const bytes& value) const + { + // RefHash(label, value) = Hash(RefHashInput) + // + // struct { + // opaque label; + // opaque value; + // } RefHashInput; + auto w = tls::ostream(); + w << label << value; + return digest().hash(w.bytes()); + } + + TLS_SERIALIZABLE(id) + +private: + ID id; + + struct Ciphers + { + hpke::HPKE hpke; + const hpke::Digest& digest; + const hpke::Signature& sig; + }; + + const Ciphers& get() const; + + template + static const bytes& reference_label(); +}; + +#if WITH_BORINGSSL +extern const std::array all_supported_suites; +#else +extern const std::array all_supported_suites; +#endif + +// Utilities +using mlspp::hpke::random_bytes; + +// HPKE Keys +namespace encrypt_label { +extern const std::string update_path_node; +extern const std::string welcome; +} // namespace encrypt_label + +struct HPKECiphertext +{ + bytes kem_output; + bytes ciphertext; + + TLS_SERIALIZABLE(kem_output, ciphertext) +}; + +struct HPKEPublicKey +{ + bytes data; + + HPKECiphertext encrypt(CipherSuite suite, + const std::string& label, + const bytes& context, + const bytes& pt) const; + + std::tuple do_export(CipherSuite suite, + const bytes& info, + const std::string& label, + size_t size) const; + + TLS_SERIALIZABLE(data) +}; + +struct HPKEPrivateKey +{ + static HPKEPrivateKey generate(CipherSuite suite); + static HPKEPrivateKey parse(CipherSuite suite, const bytes& data); + static HPKEPrivateKey derive(CipherSuite suite, const bytes& secret); + + HPKEPrivateKey() = default; + + bytes data; + HPKEPublicKey public_key; + + bytes decrypt(CipherSuite suite, + const std::string& label, + const bytes& context, + const HPKECiphertext& ct) const; + + bytes do_export(CipherSuite suite, + const bytes& info, + const bytes& kem_output, + const std::string& label, + size_t size) const; + + void set_public_key(CipherSuite suite); + + TLS_SERIALIZABLE(data) + +private: + HPKEPrivateKey(bytes priv_data, bytes pub_data); +}; + +// Signature Keys +namespace sign_label { +extern const std::string mls_content; +extern const std::string leaf_node; +extern const std::string key_package; +extern const std::string group_info; +extern const std::string multi_credential; +} // namespace sign_label + +struct SignaturePublicKey +{ + static SignaturePublicKey from_jwk(CipherSuite suite, + const std::string& json_str); + + bytes data; + + bool verify(const CipherSuite& suite, + const std::string& label, + const bytes& message, + const bytes& signature) const; + + std::string to_jwk(CipherSuite suite) const; + + TLS_SERIALIZABLE(data) +}; + +struct PublicJWK +{ + SignatureScheme signature_scheme; + std::optional key_id; + SignaturePublicKey public_key; + + static PublicJWK parse(const std::string& jwk_json); +}; + +struct SignaturePrivateKey +{ + static SignaturePrivateKey generate(CipherSuite suite); + static SignaturePrivateKey parse(CipherSuite suite, const bytes& data); + static SignaturePrivateKey derive(CipherSuite suite, const bytes& secret); + static SignaturePrivateKey from_jwk(CipherSuite suite, + const std::string& json_str); + + SignaturePrivateKey() = default; + + bytes data; + SignaturePublicKey public_key; + + bytes sign(const CipherSuite& suite, + const std::string& label, + const bytes& message) const; + + void set_public_key(CipherSuite suite); + std::string to_jwk(CipherSuite suite) const; + + TLS_SERIALIZABLE(data) + +private: + SignaturePrivateKey(bytes priv_data, bytes pub_data); +}; + +} // namespace mlspp diff --git a/mlspp/include/mls/key_schedule.h b/mlspp/include/mls/key_schedule.h new file mode 100755 index 0000000000..b30dd766e4 --- /dev/null +++ b/mlspp/include/mls/key_schedule.h @@ -0,0 +1,205 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace mlspp { + +struct HashRatchet +{ + CipherSuite suite; + bytes next_secret; + uint32_t next_generation; + std::map cache; + + size_t key_size; + size_t nonce_size; + size_t secret_size; + + // These defaults are necessary for use with containers + HashRatchet() = default; + HashRatchet(const HashRatchet& other) = default; + HashRatchet(HashRatchet&& other) = default; + HashRatchet& operator=(const HashRatchet& other) = default; + HashRatchet& operator=(HashRatchet&& other) = default; + + HashRatchet(CipherSuite suite_in, bytes base_secret_in); + + std::tuple next(); + KeyAndNonce get(uint32_t generation); + void erase(uint32_t generation); +}; + +struct SecretTree +{ + SecretTree() = default; + SecretTree(CipherSuite suite_in, + LeafCount group_size_in, + bytes encryption_secret_in); + + bool has_leaf(LeafIndex sender) { return sender < group_size; } + + bytes get(LeafIndex sender); + +private: + CipherSuite suite; + LeafCount group_size; + NodeIndex root; + std::map secrets; + size_t secret_size; +}; + +using ReuseGuard = std::array; + +struct GroupKeySource +{ + enum struct RatchetType + { + handshake, + application, + }; + + GroupKeySource() = default; + GroupKeySource(CipherSuite suite_in, + LeafCount group_size, + bytes encryption_secret); + + bool has_leaf(LeafIndex sender) { return secret_tree.has_leaf(sender); } + + std::tuple next(ContentType content_type, + LeafIndex sender); + KeyAndNonce get(ContentType content_type, + LeafIndex sender, + uint32_t generation, + ReuseGuard reuse_guard); + void erase(ContentType type, LeafIndex sender, uint32_t generation); + +private: + CipherSuite suite; + SecretTree secret_tree; + + using Key = std::tuple; + std::map chains; + + HashRatchet& chain(RatchetType type, LeafIndex sender); + HashRatchet& chain(ContentType type, LeafIndex sender); + + static const std::array all_ratchet_types; +}; + +struct KeyScheduleEpoch +{ +private: + CipherSuite suite; + +public: + bytes joiner_secret; + bytes epoch_secret; + + bytes sender_data_secret; + bytes encryption_secret; + bytes exporter_secret; + bytes epoch_authenticator; + bytes external_secret; + bytes confirmation_key; + bytes membership_key; + bytes resumption_psk; + bytes init_secret; + + HPKEPrivateKey external_priv; + + KeyScheduleEpoch() = default; + + // Full initializer, used by invited joiner + static KeyScheduleEpoch joiner(CipherSuite suite_in, + const bytes& joiner_secret, + const std::vector& psks, + const bytes& context); + + // Ciphersuite-only initializer, used by external joiner + KeyScheduleEpoch(CipherSuite suite_in); + + // Initial epoch + KeyScheduleEpoch(CipherSuite suite_in, + const bytes& init_secret, + const bytes& context); + + static std::tuple external_init( + CipherSuite suite, + const HPKEPublicKey& external_pub); + bytes receive_external_init(const bytes& kem_output) const; + + KeyScheduleEpoch next(const bytes& commit_secret, + const std::vector& psks, + const std::optional& force_init_secret, + const bytes& context) const; + + GroupKeySource encryption_keys(LeafCount size) const; + bytes confirmation_tag(const bytes& confirmed_transcript_hash) const; + bytes do_export(const std::string& label, + const bytes& context, + size_t size) const; + PSKWithSecret resumption_psk_w_secret(ResumptionPSKUsage usage, + const bytes& group_id, + epoch_t epoch); + + static bytes make_psk_secret(CipherSuite suite, + const std::vector& psks); + static bytes welcome_secret(CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks); + static KeyAndNonce sender_data_keys(CipherSuite suite, + const bytes& sender_data_secret, + const bytes& ciphertext); + + // TODO(RLB) make these methods private, but accessible to test vectors + KeyScheduleEpoch(CipherSuite suite_in, + const bytes& init_secret, + const bytes& commit_secret, + const bytes& psk_secret, + const bytes& context); + KeyScheduleEpoch next_raw(const bytes& commit_secret, + const bytes& psk_secret, + const std::optional& force_init_secret, + const bytes& context) const; + static bytes welcome_secret_raw(CipherSuite suite, + const bytes& joiner_secret, + const bytes& psk_secret); + +private: + KeyScheduleEpoch(CipherSuite suite_in, + const bytes& joiner_secret, + const bytes& psk_secret, + const bytes& context); +}; + +bool +operator==(const KeyScheduleEpoch& lhs, const KeyScheduleEpoch& rhs); + +struct TranscriptHash +{ + CipherSuite suite; + bytes confirmed; + bytes interim; + + // For a new group + TranscriptHash(CipherSuite suite_in); + + // For joining a group + TranscriptHash(CipherSuite suite_in, + bytes confirmed_in, + const bytes& confirmation_tag); + + void update(const AuthenticatedContent& content_auth); + void update_confirmed(const AuthenticatedContent& content_auth); + void update_interim(const bytes& confirmation_tag); + void update_interim(const AuthenticatedContent& content_auth); +}; + +bool +operator==(const TranscriptHash& lhs, const TranscriptHash& rhs); + +} // namespace mlspp diff --git a/mlspp/include/mls/messages.h b/mlspp/include/mls/messages.h new file mode 100755 index 0000000000..583ccc2733 --- /dev/null +++ b/mlspp/include/mls/messages.h @@ -0,0 +1,752 @@ +#pragma once + +#include "mls/common.h" +#include "mls/core_types.h" +#include "mls/credential.h" +#include "mls/crypto.h" +#include "mls/treekem.h" +#include +#include + +namespace mlspp { + +struct ExternalPubExtension +{ + HPKEPublicKey external_pub; + + static const uint16_t type; + TLS_SERIALIZABLE(external_pub) +}; + +struct RatchetTreeExtension +{ + TreeKEMPublicKey tree; + + static const uint16_t type; + TLS_SERIALIZABLE(tree) +}; + +struct ExternalSender +{ + SignaturePublicKey signature_key; + Credential credential; + + TLS_SERIALIZABLE(signature_key, credential); +}; + +struct ExternalSendersExtension +{ + std::vector senders; + + static const uint16_t type; + TLS_SERIALIZABLE(senders); +}; + +struct SFrameParameters +{ + uint16_t cipher_suite; + uint8_t epoch_bits; + + static const uint16_t type; + TLS_SERIALIZABLE(cipher_suite, epoch_bits) +}; + +struct SFrameCapabilities +{ + std::vector cipher_suites; + + bool compatible(const SFrameParameters& params) const; + + static const uint16_t type; + TLS_SERIALIZABLE(cipher_suites) +}; + +/// +/// PSKs +/// +enum struct PSKType : uint8_t +{ + reserved = 0, + external = 1, + resumption = 2, +}; + +struct ExternalPSK +{ + bytes psk_id; + TLS_SERIALIZABLE(psk_id) +}; + +enum struct ResumptionPSKUsage : uint8_t +{ + reserved = 0, + application = 1, + reinit = 2, + branch = 3, +}; + +struct ResumptionPSK +{ + ResumptionPSKUsage usage; + bytes psk_group_id; + epoch_t psk_epoch; + TLS_SERIALIZABLE(usage, psk_group_id, psk_epoch) +}; + +struct PreSharedKeyID +{ + var::variant content; + bytes psk_nonce; + TLS_SERIALIZABLE(content, psk_nonce) + TLS_TRAITS(tls::variant, tls::pass) +}; + +struct PreSharedKeys +{ + std::vector psks; + TLS_SERIALIZABLE(psks) +}; + +struct PSKWithSecret +{ + PreSharedKeyID id; + bytes secret; +}; + +// struct { +// ProtocolVersion version = mls10; +// CipherSuite cipher_suite; +// opaque group_id; +// uint64 epoch; +// opaque tree_hash; +// opaque confirmed_transcript_hash; +// Extension extensions; +// } GroupContext; +struct GroupContext +{ + ProtocolVersion version{ ProtocolVersion::mls10 }; + CipherSuite cipher_suite; + bytes group_id; + epoch_t epoch; + bytes tree_hash; + bytes confirmed_transcript_hash; + ExtensionList extensions; + + GroupContext() = default; + GroupContext(CipherSuite cipher_suite_in, + bytes group_id_in, + epoch_t epoch_in, + bytes tree_hash_in, + bytes confirmed_transcript_hash_in, + ExtensionList extensions_in); + + TLS_SERIALIZABLE(version, + cipher_suite, + group_id, + epoch, + tree_hash, + confirmed_transcript_hash, + extensions) +}; + +// struct { +// GroupContext group_context; +// Extension extensions; +// MAC confirmation_tag; +// uint32 signer; +// // SignWithLabel(., "GroupInfoTBS", GroupInfoTBS) +// opaque signature; +// } GroupInfo; +struct GroupInfo +{ + GroupContext group_context; + ExtensionList extensions; + bytes confirmation_tag; + LeafIndex signer; + bytes signature; + + GroupInfo() = default; + GroupInfo(GroupContext group_context_in, + ExtensionList extensions_in, + bytes confirmation_tag_in); + + bytes to_be_signed() const; + void sign(const TreeKEMPublicKey& tree, + LeafIndex signer_index, + const SignaturePrivateKey& priv); + bool verify(const TreeKEMPublicKey& tree) const; + + // These methods exist only to simplify unit testing + void sign(LeafIndex signer_index, const SignaturePrivateKey& priv); + bool verify(const SignaturePublicKey& pub) const; + + TLS_SERIALIZABLE(group_context, + extensions, + confirmation_tag, + signer, + signature) +}; + +// struct { +// opaque joiner_secret<1..255>; +// optional path_secret; +// PreSharedKeys psks; +// } GroupSecrets; +struct GroupSecrets +{ + struct PathSecret + { + bytes secret; + + TLS_SERIALIZABLE(secret) + }; + + bytes joiner_secret; + std::optional path_secret; + PreSharedKeys psks; + + TLS_SERIALIZABLE(joiner_secret, path_secret, psks) +}; + +// struct { +// opaque key_package_hash<1..255>; +// HPKECiphertext encrypted_group_secrets; +// } EncryptedGroupSecrets; +struct EncryptedGroupSecrets +{ + KeyPackageRef new_member; + HPKECiphertext encrypted_group_secrets; + + TLS_SERIALIZABLE(new_member, encrypted_group_secrets) +}; + +// struct { +// ProtocolVersion version = mls10; +// CipherSuite cipher_suite; +// EncryptedGroupSecrets group_secretss<1..2^32-1>; +// opaque encrypted_group_info<1..2^32-1>; +// } Welcome; +struct Welcome +{ + CipherSuite cipher_suite; + std::vector secrets; + bytes encrypted_group_info; + + Welcome(); + Welcome(CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks, + const GroupInfo& group_info); + + void encrypt(const KeyPackage& kp, const std::optional& path_secret); + std::optional find(const KeyPackage& kp) const; + GroupSecrets decrypt_secrets(int kp_index, + const HPKEPrivateKey& init_priv) const; + GroupInfo decrypt(const bytes& joiner_secret, + const std::vector& psks) const; + + TLS_SERIALIZABLE(cipher_suite, secrets, encrypted_group_info) + +private: + bytes _joiner_secret; + PreSharedKeys _psks; + static KeyAndNonce group_info_key_nonce( + CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks); +}; + +/// +/// Proposals & Commit +/// + +// Add +struct Add +{ + KeyPackage key_package; + TLS_SERIALIZABLE(key_package) +}; + +// Update +struct Update +{ + LeafNode leaf_node; + TLS_SERIALIZABLE(leaf_node) +}; + +// Remove +struct Remove +{ + LeafIndex removed; + TLS_SERIALIZABLE(removed) +}; + +// PreSharedKey +struct PreSharedKey +{ + PreSharedKeyID psk; + TLS_SERIALIZABLE(psk) +}; + +// ReInit +struct ReInit +{ + bytes group_id; + ProtocolVersion version; + CipherSuite cipher_suite; + ExtensionList extensions; + + TLS_SERIALIZABLE(group_id, version, cipher_suite, extensions) +}; + +// ExternalInit +struct ExternalInit +{ + bytes kem_output; + TLS_SERIALIZABLE(kem_output) +}; + +// GroupContextExtensions +struct GroupContextExtensions +{ + ExtensionList group_context_extensions; + TLS_SERIALIZABLE(group_context_extensions) +}; + +struct ProposalType; + +struct Proposal +{ + using Type = uint16_t; + + var::variant + content; + + Type proposal_type() const; + + TLS_SERIALIZABLE(content) + TLS_TRAITS(tls::variant) +}; + +struct ProposalType +{ + static constexpr Proposal::Type invalid = 0; + static constexpr Proposal::Type add = 1; + static constexpr Proposal::Type update = 2; + static constexpr Proposal::Type remove = 3; + static constexpr Proposal::Type psk = 4; + static constexpr Proposal::Type reinit = 5; + static constexpr Proposal::Type external_init = 6; + static constexpr Proposal::Type group_context_extensions = 7; + + constexpr ProposalType() + : val(invalid) + { + } + + constexpr ProposalType(Proposal::Type pt) + : val(pt) + { + } + + Proposal::Type val; + TLS_SERIALIZABLE(val) +}; + +enum struct ProposalOrRefType : uint8_t +{ + reserved = 0, + value = 1, + reference = 2, +}; + +struct ProposalOrRef +{ + var::variant content; + + TLS_SERIALIZABLE(content) + TLS_TRAITS(tls::variant) +}; + +// struct { +// ProposalOrRef proposals<0..2^32-1>; +// optional path; +// } Commit; +struct Commit +{ + std::vector proposals; + std::optional path; + + // Validate that the commit is acceptable as an external commit, and if so, + // produce the public key from the ExternalInit proposal + std::optional valid_external() const; + + TLS_SERIALIZABLE(proposals, path) +}; + +// struct { +// opaque group_id<0..255>; +// uint32 epoch; +// uint32 sender; +// ContentType content_type; +// +// select (PublicMessage.content_type) { +// case handshake: +// GroupOperation operation; +// opaque confirmation<0..255>; +// +// case application: +// opaque application_data<0..2^32-1>; +// } +// +// opaque signature<0..2^16-1>; +// } PublicMessage; +struct ApplicationData +{ + bytes data; + TLS_SERIALIZABLE(data) +}; + +struct GroupContext; + +enum struct WireFormat : uint16_t +{ + reserved = 0, + mls_public_message = 1, + mls_private_message = 2, + mls_welcome = 3, + mls_group_info = 4, + mls_key_package = 5, +}; + +enum struct ContentType : uint8_t +{ + invalid = 0, + application = 1, + proposal = 2, + commit = 3, +}; + +enum struct SenderType : uint8_t +{ + invalid = 0, + member = 1, + external = 2, + new_member_proposal = 3, + new_member_commit = 4, +}; + +struct MemberSender +{ + LeafIndex sender; + TLS_SERIALIZABLE(sender); +}; + +struct ExternalSenderIndex +{ + uint32_t sender_index; + TLS_SERIALIZABLE(sender_index) +}; + +struct NewMemberProposalSender +{ + TLS_SERIALIZABLE() +}; + +struct NewMemberCommitSender +{ + TLS_SERIALIZABLE() +}; + +struct Sender +{ + var::variant + sender; + + SenderType sender_type() const; + + TLS_SERIALIZABLE(sender) + TLS_TRAITS(tls::variant) +}; + +/// +/// MLSMessage and friends +/// +struct GroupKeySource; + +struct GroupContent +{ + using RawContent = var::variant; + + bytes group_id; + epoch_t epoch; + Sender sender; + bytes authenticated_data; + RawContent content; + + GroupContent() = default; + GroupContent(bytes group_id_in, + epoch_t epoch_in, + Sender sender_in, + bytes authenticated_data_in, + RawContent content_in); + GroupContent(bytes group_id_in, + epoch_t epoch_in, + Sender sender_in, + bytes authenticated_data_in, + ContentType content_type); + + ContentType content_type() const; + + TLS_SERIALIZABLE(group_id, epoch, sender, authenticated_data, content) + TLS_TRAITS(tls::pass, + tls::pass, + tls::pass, + tls::pass, + tls::variant) +}; + +struct GroupContentAuthData +{ + ContentType content_type = ContentType::invalid; + bytes signature; + std::optional confirmation_tag; + + friend tls::ostream& operator<<(tls::ostream& str, + const GroupContentAuthData& obj); + friend tls::istream& operator>>(tls::istream& str, GroupContentAuthData& obj); + friend bool operator==(const GroupContentAuthData& lhs, + const GroupContentAuthData& rhs); +}; + +struct AuthenticatedContent +{ + WireFormat wire_format; + GroupContent content; + GroupContentAuthData auth; + + AuthenticatedContent() = default; + + static AuthenticatedContent sign(WireFormat wire_format, + GroupContent content, + CipherSuite suite, + const SignaturePrivateKey& sig_priv, + const std::optional& context); + bool verify(CipherSuite suite, + const SignaturePublicKey& sig_pub, + const std::optional& context) const; + + bytes confirmed_transcript_hash_input() const; + bytes interim_transcript_hash_input() const; + + void set_confirmation_tag(const bytes& confirmation_tag); + bool check_confirmation_tag(const bytes& confirmation_tag) const; + + friend tls::ostream& operator<<(tls::ostream& str, + const AuthenticatedContent& obj); + friend tls::istream& operator>>(tls::istream& str, AuthenticatedContent& obj); + friend bool operator==(const AuthenticatedContent& lhs, + const AuthenticatedContent& rhs); + +private: + AuthenticatedContent(WireFormat wire_format_in, GroupContent content_in); + AuthenticatedContent(WireFormat wire_format_in, + GroupContent content_in, + GroupContentAuthData auth_in); + + bytes to_be_signed(const std::optional& context) const; + + friend struct PublicMessage; + friend struct PrivateMessage; +}; + +struct ValidatedContent +{ + const AuthenticatedContent& authenticated_content() const; + + friend bool operator==(const ValidatedContent& lhs, + const ValidatedContent& rhs); + +private: + AuthenticatedContent content_auth; + + ValidatedContent(AuthenticatedContent content_auth_in); + + friend struct PublicMessage; + friend struct PrivateMessage; + friend class State; +}; + +struct PublicMessage +{ + PublicMessage() = default; + + bytes get_group_id() const { return content.group_id; } + epoch_t get_epoch() const { return content.epoch; } + + static PublicMessage protect(AuthenticatedContent content_auth, + CipherSuite suite, + const std::optional& membership_key, + const std::optional& context); + std::optional unprotect( + CipherSuite suite, + const std::optional& membership_key, + const std::optional& context) const; + + bool contains(const AuthenticatedContent& content_auth) const; + + // TODO(RLB) Make this private and expose only to tests + AuthenticatedContent authenticated_content() const; + + friend tls::ostream& operator<<(tls::ostream& str, const PublicMessage& obj); + friend tls::istream& operator>>(tls::istream& str, PublicMessage& obj); + friend bool operator==(const PublicMessage& lhs, const PublicMessage& rhs); + friend bool operator!=(const PublicMessage& lhs, const PublicMessage& rhs); + +private: + GroupContent content; + GroupContentAuthData auth; + std::optional membership_tag; + + PublicMessage(AuthenticatedContent content_auth); + + bytes membership_mac(CipherSuite suite, + const bytes& membership_key, + const std::optional& context) const; +}; + +struct PrivateMessage +{ + PrivateMessage() = default; + + bytes get_group_id() const { return group_id; } + epoch_t get_epoch() const { return epoch; } + + static PrivateMessage protect(AuthenticatedContent content_auth, + CipherSuite suite, + GroupKeySource& keys, + const bytes& sender_data_secret, + size_t padding_size); + std::optional unprotect( + CipherSuite suite, + GroupKeySource& keys, + const bytes& sender_data_secret) const; + + TLS_SERIALIZABLE(group_id, + epoch, + content_type, + authenticated_data, + encrypted_sender_data, + ciphertext) + +private: + bytes group_id; + epoch_t epoch; + ContentType content_type; + bytes authenticated_data; + bytes encrypted_sender_data; + bytes ciphertext; + + PrivateMessage(GroupContent content, + bytes encrypted_sender_data_in, + bytes ciphertext_in); +}; + +struct MLSMessage +{ + ProtocolVersion version = ProtocolVersion::mls10; + var::variant + message; + + bytes group_id() const; + epoch_t epoch() const; + WireFormat wire_format() const; + + MLSMessage() = default; + MLSMessage(PublicMessage public_message); + MLSMessage(PrivateMessage private_message); + MLSMessage(Welcome welcome); + MLSMessage(GroupInfo group_info); + MLSMessage(KeyPackage key_package); + + TLS_SERIALIZABLE(version, message) + TLS_TRAITS(tls::pass, tls::variant) +}; + +MLSMessage +external_proposal(CipherSuite suite, + const bytes& group_id, + epoch_t epoch, + const Proposal& proposal, + uint32_t signer_index, + const SignaturePrivateKey& sig_priv); + +} // namespace mlspp + +namespace mlspp::tls { + +TLS_VARIANT_MAP(mlspp::PSKType, mlspp::ExternalPSK, external) +TLS_VARIANT_MAP(mlspp::PSKType, + mlspp::ResumptionPSK, + resumption) + +TLS_VARIANT_MAP(mlspp::ProposalOrRefType, + mlspp::Proposal, + value) +TLS_VARIANT_MAP(mlspp::ProposalOrRefType, + mlspp::ProposalRef, + reference) + +TLS_VARIANT_MAP(mlspp::ProposalType, mlspp::Add, add) +TLS_VARIANT_MAP(mlspp::ProposalType, mlspp::Update, update) +TLS_VARIANT_MAP(mlspp::ProposalType, mlspp::Remove, remove) +TLS_VARIANT_MAP(mlspp::ProposalType, mlspp::PreSharedKey, psk) +TLS_VARIANT_MAP(mlspp::ProposalType, mlspp::ReInit, reinit) +TLS_VARIANT_MAP(mlspp::ProposalType, + mlspp::ExternalInit, + external_init) +TLS_VARIANT_MAP(mlspp::ProposalType, + mlspp::GroupContextExtensions, + group_context_extensions) + +TLS_VARIANT_MAP(mlspp::ContentType, + mlspp::ApplicationData, + application) +TLS_VARIANT_MAP(mlspp::ContentType, mlspp::Proposal, proposal) +TLS_VARIANT_MAP(mlspp::ContentType, mlspp::Commit, commit) + +TLS_VARIANT_MAP(mlspp::SenderType, mlspp::MemberSender, member) +TLS_VARIANT_MAP(mlspp::SenderType, + mlspp::ExternalSenderIndex, + external) +TLS_VARIANT_MAP(mlspp::SenderType, + mlspp::NewMemberProposalSender, + new_member_proposal) +TLS_VARIANT_MAP(mlspp::SenderType, + mlspp::NewMemberCommitSender, + new_member_commit) + +TLS_VARIANT_MAP(mlspp::WireFormat, + mlspp::PublicMessage, + mls_public_message) +TLS_VARIANT_MAP(mlspp::WireFormat, + mlspp::PrivateMessage, + mls_private_message) +TLS_VARIANT_MAP(mlspp::WireFormat, mlspp::Welcome, mls_welcome) +TLS_VARIANT_MAP(mlspp::WireFormat, + mlspp::GroupInfo, + mls_group_info) +TLS_VARIANT_MAP(mlspp::WireFormat, + mlspp::KeyPackage, + mls_key_package) + +} // namespace mlspp::tls diff --git a/mlspp/include/mls/session.h b/mlspp/include/mls/session.h new file mode 100755 index 0000000000..045fbfdb7e --- /dev/null +++ b/mlspp/include/mls/session.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace mlspp { + +class PendingJoin; +class Session; + +class Client +{ +public: + Client(CipherSuite suite_in, + SignaturePrivateKey sig_priv_in, + Credential cred_in); + + Session begin_session(const bytes& group_id) const; + + PendingJoin start_join() const; + +private: + const CipherSuite suite; + const SignaturePrivateKey sig_priv; + const Credential cred; +}; + +class PendingJoin +{ +public: + PendingJoin(PendingJoin&& other) noexcept; + PendingJoin& operator=(PendingJoin&& other) noexcept; + ~PendingJoin(); + bytes key_package() const; + Session complete(const bytes& welcome) const; + +private: + struct Inner; + std::unique_ptr inner; + + PendingJoin(Inner* inner); + friend class Client; +}; + +class Session +{ +public: + Session(Session&& other) noexcept; + Session& operator=(Session&& other) noexcept; + ~Session(); + + // Settings + void encrypt_handshake(bool enabled); + + // Message producers + bytes add(const bytes& key_package_data); + bytes update(); + bytes remove(uint32_t index); + std::tuple commit(const bytes& proposal); + std::tuple commit(const std::vector& proposals); + std::tuple commit(); + + // Message consumers + bool handle(const bytes& handshake_data); + + // Information about the current state + epoch_t epoch() const; + LeafIndex index() const; + CipherSuite cipher_suite() const; + const ExtensionList& extensions() const; + const TreeKEMPublicKey& tree() const; + bytes do_export(const std::string& label, + const bytes& context, + size_t size) const; + GroupInfo group_info() const; + std::vector roster() const; + bytes epoch_authenticator() const; + + // Application message protection + bytes protect(const bytes& plaintext); + bytes unprotect(const bytes& ciphertext); + +protected: + struct Inner; + std::unique_ptr inner; + + Session(Inner* inner); + friend class Client; + friend class PendingJoin; + + friend bool operator==(const Session& lhs, const Session& rhs); + friend bool operator!=(const Session& lhs, const Session& rhs); +}; + +} // namespace mlspp diff --git a/mlspp/include/mls/state.h b/mlspp/include/mls/state.h new file mode 100755 index 0000000000..84e4926263 --- /dev/null +++ b/mlspp/include/mls/state.h @@ -0,0 +1,431 @@ +#pragma once + +#include "mls/crypto.h" +#include "mls/key_schedule.h" +#include "mls/messages.h" +#include "mls/treekem.h" +#include +#include +#include + +namespace mlspp { + +// Index into the session roster +struct RosterIndex : public UInt32 +{ + using UInt32::UInt32; +}; + +struct CommitOpts +{ + std::vector extra_proposals; + bool inline_tree; + bool force_path; + LeafNodeOptions leaf_node_opts; +}; + +struct MessageOpts +{ + bool encrypt = false; + bytes authenticated_data; + size_t padding_size = 0; +}; + +class State +{ +public: + /// + /// Constructors + /// + + // Initialize an empty group + State(bytes group_id, + CipherSuite suite, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + ExtensionList extensions); + + // Initialize a group from a Welcome + State(const HPKEPrivateKey& init_priv, + HPKEPrivateKey leaf_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree, + std::map psks); + + // Join a group from outside + // XXX(RLB) To be fully general, we would need a few more options here, e.g., + // whether to include PSKs or evict our prior appearance. + static std::tuple external_join( + const bytes& leaf_secret, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const GroupInfo& group_info, + const std::optional& tree, + const MessageOpts& msg_opts, + std::optional remove_prior, + const std::map& psks); + + // Propose that a new member be added a group + static MLSMessage new_member_add(const bytes& group_id, + epoch_t epoch, + const KeyPackage& new_member, + const SignaturePrivateKey& sig_priv); + + /// + /// Message factories + /// + + Proposal add_proposal(const KeyPackage& key_package) const; + Proposal update_proposal(HPKEPrivateKey leaf_priv, + const LeafNodeOptions& opts); + Proposal remove_proposal(RosterIndex index) const; + Proposal remove_proposal(LeafIndex removed) const; + Proposal group_context_extensions_proposal(ExtensionList exts) const; + Proposal pre_shared_key_proposal(const bytes& external_psk_id) const; + Proposal pre_shared_key_proposal(const bytes& group_id, epoch_t epoch) const; + static Proposal reinit_proposal(bytes group_id, + ProtocolVersion version, + CipherSuite cipher_suite, + ExtensionList extensions); + + MLSMessage add(const KeyPackage& key_package, const MessageOpts& msg_opts); + MLSMessage update(HPKEPrivateKey leaf_priv, + const LeafNodeOptions& opts, + const MessageOpts& msg_opts); + MLSMessage remove(RosterIndex index, const MessageOpts& msg_opts); + MLSMessage remove(LeafIndex removed, const MessageOpts& msg_opts); + MLSMessage group_context_extensions(ExtensionList exts, + const MessageOpts& msg_opts); + MLSMessage pre_shared_key(const bytes& external_psk_id, + const MessageOpts& msg_opts); + MLSMessage pre_shared_key(const bytes& group_id, + epoch_t epoch, + const MessageOpts& msg_opts); + MLSMessage reinit(bytes group_id, + ProtocolVersion version, + CipherSuite cipher_suite, + ExtensionList extensions, + const MessageOpts& msg_opts); + + std::tuple commit( + const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts); + + /// + /// Generic handshake message handlers + /// + std::optional handle(const MLSMessage& msg); + std::optional handle(const MLSMessage& msg, + std::optional cached_state); + + std::optional handle(const ValidatedContent& content_auth); + std::optional handle(const ValidatedContent& content_auth, + std::optional cached_state); + + /// + /// PSK management + /// + void add_resumption_psk(const bytes& group_id, epoch_t epoch, bytes secret); + void remove_resumption_psk(const bytes& group_id, epoch_t epoch); + void add_external_psk(const bytes& id, const bytes& secret); + void remove_external_psk(const bytes& id); + + /// + /// Accessors + /// + const bytes& group_id() const { return _group_id; } + epoch_t epoch() const { return _epoch; } + LeafIndex index() const { return _index; } + CipherSuite cipher_suite() const { return _suite; } + const ExtensionList& extensions() const { return _extensions; } + const TreeKEMPublicKey& tree() const { return _tree; } + const bytes& resumption_psk() const { return _key_schedule.resumption_psk; } + + bytes do_export(const std::string& label, + const bytes& context, + size_t size) const; + GroupInfo group_info(bool inline_tree) const; + + // Ordered list of credentials from non-blank leaves + std::vector roster() const; + + bytes epoch_authenticator() const; + + /// + /// Unwrap messages so that applications can inspect them + /// + ValidatedContent unwrap(const MLSMessage& msg); + + /// + /// Application encryption and decryption + /// + MLSMessage protect(const bytes& authenticated_data, + const bytes& pt, + size_t padding_size); + std::tuple unprotect(const MLSMessage& ct); + + // Assemble a group context for this state + GroupContext group_context() const; + + // Subgroup branching + std::tuple create_branch( + bytes group_id, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + ExtensionList extensions, + const std::vector& key_packages, + const bytes& leaf_secret, + const CommitOpts& commit_opts) const; + State handle_branch(const HPKEPrivateKey& init_priv, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree) const; + + // Reinitialization + struct Tombstone + { + std::tuple create_welcome( + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + const std::vector& key_packages, + const bytes& leaf_secret, + const CommitOpts& commit_opts) const; + State handle_welcome(const HPKEPrivateKey& init_priv, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree) const; + + TLS_SERIALIZABLE(prior_group_id, prior_epoch, resumption_psk, reinit); + + const bytes epoch_authenticator; + const ReInit reinit; + + private: + Tombstone(const State& state_in, ReInit reinit_in); + + bytes prior_group_id; + epoch_t prior_epoch; + bytes resumption_psk; + + friend class State; + }; + + std::tuple reinit_commit( + const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts); + Tombstone handle_reinit_commit(const MLSMessage& commit); + +protected: + // Shared confirmed state + // XXX(rlb@ipv.sx): Can these be made const? + CipherSuite _suite; + bytes _group_id; + epoch_t _epoch; + TreeKEMPublicKey _tree; + TreeKEMPrivateKey _tree_priv; + TranscriptHash _transcript_hash; + ExtensionList _extensions; + + // Shared secret state + KeyScheduleEpoch _key_schedule; + GroupKeySource _keys; + + // Per-participant state + LeafIndex _index; + SignaturePrivateKey _identity_priv; + + // Storage for PSKs + std::map _external_psks; + + using EpochRef = std::tuple; + std::map _resumption_psks; + + // Cache of Proposals and update secrets + struct CachedProposal + { + ProposalRef ref; + Proposal proposal; + std::optional sender; + }; + std::list _pending_proposals; + + struct CachedUpdate + { + HPKEPrivateKey update_priv; + Update proposal; + }; + std::optional _cached_update; + + // Assemble a preliminary, unjoined group state + State(SignaturePrivateKey sig_priv, + const GroupInfo& group_info, + const std::optional& tree); + + // Assemble a group from a Welcome, allowing for resumption PSKs + State(const HPKEPrivateKey& init_priv, + HPKEPrivateKey leaf_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree, + std::map external_psks, + std::map resumption_psks); + + // Import a tree from an externally-provided tree or an extension + TreeKEMPublicKey import_tree(const bytes& tree_hash, + const std::optional& external, + const ExtensionList& extensions); + bool validate_tree() const; + + // Form a commit, covering all the cases with slightly different validation + // rules: + // * Normal + // * External + // * Branch + // * Reinit + struct NormalCommitParams + {}; + + struct ExternalCommitParams + { + KeyPackage joiner_key_package; + bytes force_init_secret; + }; + + struct RestartCommitParams + { + ResumptionPSKUsage allowed_usage; + }; + + struct ReInitCommitParams + {}; + + using CommitParams = var::variant; + + std::tuple commit( + const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts, + CommitParams params); + + std::optional handle( + const MLSMessage& msg, + std::optional cached_state, + const std::optional& expected_params); + std::optional handle( + const ValidatedContent& val_content, + std::optional cached_state, + const std::optional& expected_params); + + // Create an MLSMessage encapsulating some content + template + AuthenticatedContent sign(const Sender& sender, + Inner&& content, + const bytes& authenticated_data, + bool encrypt) const; + + MLSMessage protect(AuthenticatedContent&& content_auth, size_t padding_size); + + template + MLSMessage protect_full(Inner&& content, const MessageOpts& msg_opts); + + // Apply the changes requested by various messages + LeafIndex apply(const Add& add); + void apply(LeafIndex target, const Update& update); + void apply(LeafIndex target, + const Update& update, + const HPKEPrivateKey& leaf_priv); + LeafIndex apply(const Remove& remove); + void apply(const GroupContextExtensions& gce); + std::vector apply(const std::vector& proposals, + Proposal::Type required_type); + std::tuple, std::vector> apply( + const std::vector& proposals); + + // Verify that a specific key package or all members support a given set of + // extensions + bool extensions_supported(const ExtensionList& exts) const; + + // Extract proposals and PSKs from cache + void cache_proposal(AuthenticatedContent content_auth); + std::optional resolve( + const ProposalOrRef& id, + std::optional sender_index) const; + std::vector must_resolve( + const std::vector& ids, + std::optional sender_index) const; + + std::vector resolve( + const std::vector& psks) const; + + // Check properties of proposals + bool valid(const LeafNode& leaf_node, + LeafNodeSource required_source, + std::optional index) const; + bool valid(const KeyPackage& key_package) const; + bool valid(const Add& add) const; + bool valid(LeafIndex sender, const Update& update) const; + bool valid(const Remove& remove) const; + bool valid(const PreSharedKey& psk) const; + static bool valid(const ReInit& reinit); + bool valid(const ExternalInit& external_init) const; + bool valid(const GroupContextExtensions& gce) const; + bool valid(std::optional sender, const Proposal& proposal) const; + + bool valid(const std::vector& proposals, + LeafIndex commit_sender, + const CommitParams& params) const; + bool valid_normal(const std::vector& proposals, + LeafIndex commit_sender) const; + bool valid_external(const std::vector& proposals) const; + static bool valid_reinit(const std::vector& proposals); + static bool valid_restart(const std::vector& proposals, + ResumptionPSKUsage allowed_usage); + + static bool valid_external_proposal_type(const Proposal::Type proposal_type); + + CommitParams infer_commit_type( + const std::optional& sender, + const std::vector& proposals, + const std::optional& expected_params) const; + static bool path_required(const std::vector& proposals); + + // Compare the **shared** attributes of the states + friend bool operator==(const State& lhs, const State& rhs); + friend bool operator!=(const State& lhs, const State& rhs); + + // Derive and set the secrets for an epoch, given some new entropy + void update_epoch_secrets(const bytes& commit_secret, + const std::vector& psks, + const std::optional& force_init_secret); + + // Signature verification over a handshake message + bool verify_internal(const AuthenticatedContent& content_auth) const; + bool verify_external(const AuthenticatedContent& content_auth) const; + bool verify_new_member_proposal( + const AuthenticatedContent& content_auth) const; + bool verify_new_member_commit(const AuthenticatedContent& content_auth) const; + bool verify(const AuthenticatedContent& content_auth) const; + + // Convert a Roster entry into LeafIndex + LeafIndex leaf_for_roster_entry(RosterIndex index) const; + + // Create a draft successor state + State successor() const; +}; + +} // namespace mlspp diff --git a/mlspp/include/mls/tree_math.h b/mlspp/include/mls/tree_math.h new file mode 100755 index 0000000000..6a11f47a6f --- /dev/null +++ b/mlspp/include/mls/tree_math.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include +#include + +// The below functions provide the index calculus for the tree +// structures used in MLS. They are premised on a "flat" +// representation of a balanced binary tree. Leaf nodes are +// even-numbered nodes, with the n-th leaf at 2*n. Intermediate +// nodes are held in odd-numbered nodes. For example, a 11-element +// tree has the following structure: +// +// X +// X +// X X X +// X X X X X +// X X X X X X X X X X X +// 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 +// +// This allows us to compute relationships between tree nodes simply +// by manipulating indices, rather than having to maintain +// complicated structures in memory, even for partial trees. (The +// storage for a tree can just be a map[int]Node dictionary or an +// array.) The basic rule is that the high-order bits of parent and +// child nodes have the following relation: +// +// 01x = <00x, 10x> + +namespace mlspp { + +// Index types go in the overall namespace +// XXX(rlb@ipv.sx): Seems like this stuff can probably get +// simplified down a fair bit. +struct UInt32 +{ + uint32_t val; + + UInt32() + : val(0) + { + } + + explicit UInt32(uint32_t val_in) + : val(val_in) + { + } + + TLS_SERIALIZABLE(val) +}; + +struct NodeCount; + +struct LeafCount : public UInt32 +{ + using UInt32::UInt32; + explicit LeafCount(const NodeCount w); + + static LeafCount full(const LeafCount n); +}; + +struct NodeCount : public UInt32 +{ + using UInt32::UInt32; + explicit NodeCount(const LeafCount n); +}; + +struct NodeIndex; + +struct LeafIndex : public UInt32 +{ + using UInt32::UInt32; + explicit LeafIndex(const NodeIndex x); + bool operator<(const LeafIndex other) const { return val < other.val; } + bool operator<(const LeafCount other) const { return val < other.val; } + + NodeIndex ancestor(LeafIndex other) const; +}; + +struct NodeIndex : public UInt32 +{ + using UInt32::UInt32; + explicit NodeIndex(const LeafIndex x); + bool operator<(const NodeIndex other) const { return val < other.val; } + bool operator<(const NodeCount other) const { return val < other.val; } + + static NodeIndex root(LeafCount n); + + bool is_leaf() const; + bool is_below(NodeIndex other) const; + + NodeIndex left() const; + NodeIndex right() const; + NodeIndex parent() const; + NodeIndex sibling() const; + + // Returns the sibling of this node "relative to this ancestor" -- the child + // of `ancestor` that is not in the direct path of this node. + NodeIndex sibling(NodeIndex ancestor) const; + + std::vector dirpath(LeafCount n); + std::vector copath(LeafCount n); + + uint32_t level() const; +}; + +} // namespace mlspp diff --git a/mlspp/include/mls/treekem.h b/mlspp/include/mls/treekem.h new file mode 100755 index 0000000000..e3e1028d3d --- /dev/null +++ b/mlspp/include/mls/treekem.h @@ -0,0 +1,255 @@ +#pragma once + +#include "mls/common.h" +#include "mls/core_types.h" +#include "mls/crypto.h" +#include "mls/tree_math.h" +#include + +#define ENABLE_TREE_DUMP 1 + +namespace mlspp { + +enum struct NodeType : uint8_t +{ + reserved = 0x00, + leaf = 0x01, + parent = 0x02, +}; + +struct Node +{ + var::variant node; + + const HPKEPublicKey& public_key() const; + std::optional parent_hash() const; + + TLS_SERIALIZABLE(node) + TLS_TRAITS(tls::variant) +}; + +struct OptionalNode +{ + std::optional node; + + bool blank() const { return !node.has_value(); } + bool leaf() const + { + return !blank() && var::holds_alternative(opt::get(node).node); + } + + LeafNode& leaf_node() { return var::get(opt::get(node).node); } + + const LeafNode& leaf_node() const + { + return var::get(opt::get(node).node); + } + + ParentNode& parent_node() + { + return var::get(opt::get(node).node); + } + + const ParentNode& parent_node() const + { + return var::get(opt::get(node).node); + } + + TLS_SERIALIZABLE(node) +}; + +struct TreeKEMPublicKey; + +struct TreeKEMPrivateKey +{ + CipherSuite suite; + LeafIndex index; + bytes update_secret; + std::map path_secrets; + std::map private_key_cache; + + static TreeKEMPrivateKey solo(CipherSuite suite, + LeafIndex index, + HPKEPrivateKey leaf_priv); + static TreeKEMPrivateKey create(const TreeKEMPublicKey& pub, + LeafIndex from, + const bytes& leaf_secret); + static TreeKEMPrivateKey joiner(const TreeKEMPublicKey& pub, + LeafIndex index, + HPKEPrivateKey leaf_priv, + NodeIndex intersect, + const std::optional& path_secret); + + void set_leaf_priv(HPKEPrivateKey priv); + std::tuple shared_path_secret(LeafIndex to) const; + + bool have_private_key(NodeIndex n) const; + std::optional private_key(NodeIndex n); + std::optional private_key(NodeIndex n) const; + + void decap(LeafIndex from, + const TreeKEMPublicKey& pub, + const bytes& context, + const UpdatePath& path, + const std::vector& except); + + void truncate(LeafCount size); + + bool consistent(const TreeKEMPrivateKey& other) const; + bool consistent(const TreeKEMPublicKey& other) const; + +#if ENABLE_TREE_DUMP + void dump() const; +#endif + + // TODO(RLB) Make this private but exposed to test vectors + void implant(const TreeKEMPublicKey& pub, + NodeIndex start, + const bytes& path_secret); +}; + +struct TreeKEMPublicKey +{ + CipherSuite suite; + LeafCount size{ 0 }; + std::vector nodes; + + explicit TreeKEMPublicKey(CipherSuite suite); + + TreeKEMPublicKey() = default; + TreeKEMPublicKey(const TreeKEMPublicKey& other) = default; + TreeKEMPublicKey(TreeKEMPublicKey&& other) = default; + TreeKEMPublicKey& operator=(const TreeKEMPublicKey& other) = default; + TreeKEMPublicKey& operator=(TreeKEMPublicKey&& other) = default; + + LeafIndex allocate_leaf(); + LeafIndex add_leaf(const LeafNode& leaf); + void update_leaf(LeafIndex index, const LeafNode& leaf); + void blank_path(LeafIndex index); + + TreeKEMPrivateKey update(LeafIndex from, + const bytes& leaf_secret, + const bytes& group_id, + const SignaturePrivateKey& sig_priv, + const LeafNodeOptions& opts); + UpdatePath encap(const TreeKEMPrivateKey& priv, + const bytes& context, + const std::vector& except) const; + + void merge(LeafIndex from, const UpdatePath& path); + void set_hash_all(); + const bytes& get_hash(NodeIndex index); + bytes root_hash() const; + + bool parent_hash_valid(LeafIndex from, const UpdatePath& path) const; + bool parent_hash_valid() const; + + bool has_leaf(LeafIndex index) const; + std::optional find(const LeafNode& leaf) const; + std::optional leaf_node(LeafIndex index) const; + std::vector resolve(NodeIndex index) const; + + template + bool all_leaves(const UnaryPredicate& pred) const + { + for (LeafIndex i{ 0 }; i < size; i.val++) { + const auto& node = node_at(i); + if (node.blank()) { + continue; + } + + if (!pred(i, node.leaf_node())) { + return false; + } + } + + return true; + } + + template + bool any_leaf(const UnaryPredicate& pred) const + { + for (LeafIndex i{ 0 }; i < size; i.val++) { + const auto& node = node_at(i); + if (node.blank()) { + continue; + } + + if (pred(i, node.leaf_node())) { + return true; + } + } + + return false; + } + + using FilteredDirectPath = + std::vector>>; + FilteredDirectPath filtered_direct_path(NodeIndex index) const; + + void truncate(); + + OptionalNode& node_at(NodeIndex n); + const OptionalNode& node_at(NodeIndex n) const; + OptionalNode& node_at(LeafIndex n); + const OptionalNode& node_at(LeafIndex n) const; + + TLS_SERIALIZABLE(nodes) + +#if ENABLE_TREE_DUMP + void dump() const; +#endif + +private: + std::map hashes; + + void clear_hash_all(); + void clear_hash_path(LeafIndex index); + + bool has_parent_hash(NodeIndex child, const bytes& target_ph) const; + + bytes parent_hash(const ParentNode& parent, NodeIndex copath_child) const; + std::vector parent_hashes( + LeafIndex from, + const FilteredDirectPath& fdp, + const std::vector& path_nodes) const; + + using TreeHashCache = std::map>; + const bytes& original_tree_hash(TreeHashCache& cache, + NodeIndex index, + std::vector parent_except) const; + bytes original_parent_hash(TreeHashCache& cache, + NodeIndex parent, + NodeIndex sibling) const; + + bool exists_in_tree(const HPKEPublicKey& key, + std::optional except) const; + bool exists_in_tree(const SignaturePublicKey& key, + std::optional except) const; + + OptionalNode blank_node; + + friend struct TreeKEMPrivateKey; +}; + +tls::ostream& +operator<<(tls::ostream& str, const TreeKEMPublicKey& obj); +tls::istream& +operator>>(tls::istream& str, TreeKEMPublicKey& obj); + +struct LeafNodeHashInput; +struct ParentNodeHashInput; + +} // namespace mlspp + +namespace mlspp::tls { + +TLS_VARIANT_MAP(mlspp::NodeType, mlspp::LeafNodeHashInput, leaf) +TLS_VARIANT_MAP(mlspp::NodeType, + mlspp::ParentNodeHashInput, + parent) + +TLS_VARIANT_MAP(mlspp::NodeType, mlspp::LeafNode, leaf) +TLS_VARIANT_MAP(mlspp::NodeType, mlspp::ParentNode, parent) + +} // namespace mlspp::tls diff --git a/mlspp/include/namespace.h b/mlspp/include/namespace.h new file mode 100755 index 0000000000..d07ba5ee94 --- /dev/null +++ b/mlspp/include/namespace.h @@ -0,0 +1,4 @@ +#pragma once + +// Configurable top-level MLS namespace +#define MLS_NAMESPACE ../include/dpp/mlspp/mls diff --git a/mlspp/include/version.h b/mlspp/include/version.h new file mode 100755 index 0000000000..0cead31c4e --- /dev/null +++ b/mlspp/include/version.h @@ -0,0 +1,5 @@ +#pragma once + +/* Global version strings */ +extern const char VERSION[]; +extern const char HASHVAR[]; diff --git a/mlspp/lib/CMakeLists.txt b/mlspp/lib/CMakeLists.txt new file mode 100755 index 0000000000..31f9546e84 --- /dev/null +++ b/mlspp/lib/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(bytes) +add_subdirectory(hpke) +add_subdirectory(tls_syntax) +add_subdirectory(mls_vectors) diff --git a/mlspp/lib/bytes/CMakeLists.txt b/mlspp/lib/bytes/CMakeLists.txt new file mode 100755 index 0000000000..ee4bb15937 --- /dev/null +++ b/mlspp/lib/bytes/CMakeLists.txt @@ -0,0 +1,25 @@ +set(CURRENT_LIB_NAME bytes) + +### +### Library Config +### + +file(GLOB_RECURSE LIB_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +add_library(${CURRENT_LIB_NAME} STATIC ${LIB_HEADERS} ${LIB_SOURCES}) +add_dependencies(${CURRENT_LIB_NAME} tls_syntax) +include_directories("${PROJECT_SOURCE_DIR}/../bytes/include") +target_link_libraries(${CURRENT_LIB_NAME} tls_syntax) +target_include_directories(${CURRENT_LIB_NAME} + PUBLIC + $ + $ + $ +) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/bytes/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/hpke/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/mls_vectors/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/tls_syntax/include") + diff --git a/mlspp/lib/bytes/include/bytes/bytes.h b/mlspp/lib/bytes/include/bytes/bytes.h new file mode 100755 index 0000000000..094466f791 --- /dev/null +++ b/mlspp/lib/bytes/include/bytes/bytes.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include + +namespace mlspp::bytes_ns { + +struct bytes +{ + // Ensure defaults + bytes() = default; + bytes(const bytes&) = default; + bytes& operator=(const bytes&) = default; + bytes(bytes&&) = default; + bytes& operator=(bytes&&) = default; + + // Zeroize on drop + ~bytes() + { + auto ptr = static_cast(_data.data()); + std::fill(ptr, ptr + _data.size(), uint8_t(0)); + } + + // Mimic std::vector ctors + bytes(size_t count, const uint8_t& value = 0) + : _data(count, value) + { + } + + bytes(std::initializer_list init) + : _data(init) + { + } + + template + bytes(const std::array& data) + : _data(data.begin(), data.end()) + { + } + + // Slice out sub-vectors (to avoid an iterator ctor) + bytes slice(size_t begin_index, size_t end_index) const + { + const auto begin_it = _data.begin() + begin_index; + const auto end_it = _data.begin() + end_index; + return std::vector(begin_it, end_it); + } + + // Freely convert to/from std::vector + bytes(const std::vector& vec) + : _data(vec) + { + } + + bytes(std::vector&& vec) + : _data(vec) + { + } + + operator const std::vector&() const { return _data; } + operator std::vector&() { return _data; } + operator std::vector&&() && { return std::move(_data); } + + const std::vector& as_vec() const { return _data; } + std::vector& as_vec() { return _data; } + + // Pass through methods + auto data() const { return _data.data(); } + auto data() { return _data.data(); } + + auto size() const { return _data.size(); } + auto empty() const { return _data.empty(); } + + auto begin() const { return _data.begin(); } + auto begin() { return _data.begin(); } + + auto end() const { return _data.end(); } + auto end() { return _data.end(); } + + const auto& at(size_t pos) const { return _data.at(pos); } + auto& at(size_t pos) { return _data.at(pos); } + + void resize(size_t count) { _data.resize(count); } + void reserve(size_t len) { _data.reserve(len); } + void push_back(uint8_t byte) { _data.push_back(byte); } + + // Equality operators + bool operator==(const bytes& other) const; + bool operator!=(const bytes& other) const; + + bool operator==(const std::vector& other) const; + bool operator!=(const std::vector& other) const; + + // Arithmetic operators + bytes& operator+=(const bytes& other); + bytes operator+(const bytes& rhs) const; + bytes operator^(const bytes& rhs) const; + + // Sorting operators (to allow usage as map keys) + bool operator<(const bytes& rhs) const; + + // Other, external operators + friend std::ostream& operator<<(std::ostream& out, const bytes& data); + friend bool operator==(const std::vector& lhs, const bytes& rhs); + friend bool operator!=(const std::vector& lhs, const bytes& rhs); + + // TLS syntax serialization + TLS_SERIALIZABLE(_data); + +private: + std::vector _data; +}; + +std::string +to_ascii(const bytes& data); + +bytes +from_ascii(const std::string& ascii); + +std::string +to_hex(const bytes& data); + +bytes +from_hex(const std::string& hex); + +} // namespace mlspp::bytes_ns diff --git a/mlspp/lib/bytes/include/tls/compat.h b/mlspp/lib/bytes/include/tls/compat.h new file mode 100755 index 0000000000..095cc17ff6 --- /dev/null +++ b/mlspp/lib/bytes/include/tls/compat.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#ifdef VARIANT_COMPAT +#include +#else +#include +#endif // VARIANT_COMPAT + +namespace mlspp::tls { + +namespace var = std; + +// In a similar vein, we provide our own safe accessors for std::optional, since +// std::optional::value() is not available on macOS 10.11. +namespace opt { + +template +T& +get(std::optional& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return *opt; +} + +template +const T& +get(const std::optional& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return *opt; +} + +template +T&& +get(std::optional&& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return std::move(*opt); +} + +template +const T&& +get(const std::optional&& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return std::move(*opt); +} + +} // namespace opt +} // namespace mlspp::tls diff --git a/mlspp/lib/bytes/include/tls/tls_syntax.h b/mlspp/lib/bytes/include/tls/tls_syntax.h new file mode 100755 index 0000000000..09d5940d9d --- /dev/null +++ b/mlspp/lib/bytes/include/tls/tls_syntax.h @@ -0,0 +1,569 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mlspp::tls { + +// For indicating no min or max in vector definitions +const size_t none = std::numeric_limits::max(); + +class WriteError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class ReadError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +/// +/// Declarations of Streams and Traits +/// + +class ostream +{ +public: + static const size_t none = std::numeric_limits::max(); + + void write_raw(const std::vector& bytes); + + const std::vector& bytes() const { return _buffer; } + size_t size() const { return _buffer.size(); } + bool empty() const { return _buffer.empty(); } + +private: + std::vector _buffer; + ostream& write_uint(uint64_t value, int length); + + friend ostream& operator<<(ostream& out, bool data); + friend ostream& operator<<(ostream& out, uint8_t data); + friend ostream& operator<<(ostream& out, uint16_t data); + friend ostream& operator<<(ostream& out, uint32_t data); + friend ostream& operator<<(ostream& out, uint64_t data); + + template + friend ostream& operator<<(ostream& out, const std::vector& data); + + friend struct varint; +}; + +class istream +{ +public: + istream(const std::vector& data) + : _buffer(data) + { + // So that we can use the constant-time pop_back + std::reverse(_buffer.begin(), _buffer.end()); + } + + size_t size() const { return _buffer.size(); } + bool empty() const { return _buffer.empty(); } + + std::vector bytes() + { + auto bytes = _buffer; + std::reverse(bytes.begin(), bytes.end()); + return bytes; + } + +private: + istream() {} + std::vector _buffer; + uint8_t next(); + + template + istream& read_uint(T& data, size_t length) + { + uint64_t value = 0; + for (size_t i = 0; i < length; i += 1) { + value = (value << unsigned(8)) + next(); + } + data = static_cast(value); + return *this; + } + + friend istream& operator>>(istream& in, bool& data); + friend istream& operator>>(istream& in, uint8_t& data); + friend istream& operator>>(istream& in, uint16_t& data); + friend istream& operator>>(istream& in, uint32_t& data); + friend istream& operator>>(istream& in, uint64_t& data); + + template + friend istream& operator>>(istream& in, std::vector& data); + + friend struct varint; +}; + +// Traits must have static encode and decode methods, of the following form: +// +// static ostream& encode(ostream& str, const T& val); +// static istream& decode(istream& str, T& val); +// +// Trait types will never be constructed; only these static methods are used. +// The value arguments to encode and decode can be as strict or as loose as +// desired. +// +// Ultimately, all interesting encoding should be done through traits. +// +// * vectors +// * variants +// * varints + +struct pass +{ + template + static ostream& encode(ostream& str, const T& val); + + template + static istream& decode(istream& str, T& val); +}; + +template +struct variant +{ + template + static inline Ts type(const var::variant& data); + + template + static ostream& encode(ostream& str, const var::variant& data); + + template + static inline typename std::enable_if::type + read_variant(istream&, Te, var::variant&); + + template + static inline typename std::enable_if < + I::type read_variant(istream& str, + Te target_type, + var::variant& v); + + template + static istream& decode(istream& str, var::variant& data); +}; + +struct varint +{ + static ostream& encode(ostream& str, const uint64_t& val); + static istream& decode(istream& str, uint64_t& val); +}; + +/// +/// Writer implementations +/// + +// Primitive writers defined in .cpp file + +// Array writer +template +ostream& +operator<<(ostream& out, const std::array& data) +{ + for (const auto& item : data) { + out << item; + } + return out; +} + +// Optional writer +template +ostream& +operator<<(ostream& out, const std::optional& opt) +{ + if (!opt) { + return out << uint8_t(0); + } + + return out << uint8_t(1) << opt::get(opt); +} + +// Enum writer +template::value, int> = 0> +ostream& +operator<<(ostream& str, const T& val) +{ + auto u = static_cast>(val); + return str << u; +} + +// Vector writer +template +ostream& +operator<<(ostream& str, const std::vector& vec) +{ + // Pre-encode contents + ostream temp; + for (const auto& item : vec) { + temp << item; + } + + // Write the encoded length, then the pre-encoded data + varint::encode(str, temp._buffer.size()); + str.write_raw(temp.bytes()); + + return str; +} + +/// +/// Reader implementations +/// + +// Primitive type readers defined in .cpp file + +// Array reader +template +istream& +operator>>(istream& in, std::array& data) +{ + for (auto& item : data) { + in >> item; + } + return in; +} + +// Optional reader +template +istream& +operator>>(istream& in, std::optional& opt) +{ + uint8_t present = 0; + in >> present; + + switch (present) { + case 0: + opt.reset(); + return in; + + case 1: + opt.emplace(); + return in >> opt::get(opt); + + default: + throw std::invalid_argument("Malformed optional"); + } +} + +// Enum reader +// XXX(rlb): It would be nice if this could enforce that the values are valid, +// but C++ doesn't seem to have that ability. When used as a tag for variants, +// the variant reader will enforce, at least. +template::value, int> = 0> +istream& +operator>>(istream& str, T& val) +{ + std::underlying_type_t u; + str >> u; + val = static_cast(u); + return str; +} + +// Vector reader +template +istream& +operator>>(istream& str, std::vector& vec) +{ + // Read the encoded data size + auto size = uint64_t(0); + varint::decode(str, size); + if (size > str._buffer.size()) { + throw ReadError("Vector is longer than remaining data"); + } + + // Read the elements of the vector + // NB: Remember that we store the vector in reverse order + // NB: This requires that T be default-constructible + istream r; + r._buffer = + std::vector{ str._buffer.end() - size, str._buffer.end() }; + + vec.clear(); + while (r._buffer.size() > 0) { + vec.emplace_back(); + r >> vec.back(); + } + + // Truncate the primary buffer + str._buffer.erase(str._buffer.end() - size, str._buffer.end()); + + return str; +} + +// Abbreviations +template +std::vector +marshal(const T& value) +{ + ostream w; + w << value; + return w.bytes(); +} + +template +void +unmarshal(const std::vector& data, T& value) +{ + istream r(data); + r >> value; +} + +template +T +get(const std::vector& data, Tp... args) +{ + T value(args...); + unmarshal(data, value); + return value; +} + +// Use this macro to define struct serialization with minimal boilerplate +#define TLS_SERIALIZABLE(...) \ + static const bool _tls_serializable = true; \ + auto _tls_fields_r() \ + { \ + return std::forward_as_tuple(__VA_ARGS__); \ + } \ + auto _tls_fields_w() const \ + { \ + return std::forward_as_tuple(__VA_ARGS__); \ + } + +// If your struct contains nontrivial members (e.g., vectors), use this to +// define traits for them. +#define TLS_TRAITS(...) \ + static const bool _tls_has_traits = true; \ + using _tls_traits = std::tuple<__VA_ARGS__>; + +template +struct is_serializable +{ + template + static std::true_type test(decltype(U::_tls_serializable)); + + template + static std::false_type test(...); + + static const bool value = decltype(test(true))::value; +}; + +template +struct has_traits +{ + template + static std::true_type test(decltype(U::_tls_has_traits)); + + template + static std::false_type test(...); + + static const bool value = decltype(test(true))::value; +}; + +/// +/// Trait implementations +/// + +// Pass-through (normal encoding/decoding) +template +ostream& +pass::encode(ostream& str, const T& val) +{ + return str << val; +} + +template +istream& +pass::decode(istream& str, T& val) +{ + return str >> val; +} + +// Variant encoding +template +constexpr Ts +variant_map(); + +#define TLS_VARIANT_MAP(EnumType, MappedType, enum_value) \ + template<> \ + constexpr EnumType variant_map() \ + { \ + return EnumType::enum_value; \ + } + +template +template +inline Ts +variant::type(const var::variant& data) +{ + const auto get_type = [](const auto& v) { + return variant_map>(); + }; + return var::visit(get_type, data); +} + +template +template +ostream& +variant::encode(ostream& str, const var::variant& data) +{ + const auto write_variant = [&str](auto&& v) { + using Tv = std::decay_t; + str << variant_map() << v; + }; + var::visit(write_variant, data); + return str; +} + +template +template +inline typename std::enable_if::type +variant::read_variant(istream&, Te, var::variant&) +{ + throw ReadError("Invalid variant type label"); +} + +template + template + inline + typename std::enable_if < I::type + variant::read_variant(istream& str, + Te target_type, + var::variant& v) +{ + using Tc = var::variant_alternative_t>; + if (variant_map() == target_type) { + str >> v.template emplace(); + return; + } + + read_variant(str, target_type, v); +} + +template +template +istream& +variant::decode(istream& str, var::variant& data) +{ + Ts target_type; + str >> target_type; + read_variant(str, target_type, data); + return str; +} + +// Struct writer without traits (enabled by macro) +template +inline typename std::enable_if::type +write_tuple(ostream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + write_tuple(ostream& str, const std::tuple& t) +{ + str << std::get(t); + write_tuple(str, t); +} + +template +inline + typename std::enable_if::value && !has_traits::value, + ostream&>::type + operator<<(ostream& str, const T& obj) +{ + write_tuple(str, obj._tls_fields_w()); + return str; +} + +// Struct writer with traits (enabled by macro) +template +inline typename std::enable_if::type +write_tuple_traits(ostream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + write_tuple_traits(ostream& str, const std::tuple& t) +{ + std::tuple_element_t::encode(str, std::get(t)); + write_tuple_traits(str, t); +} + +template +inline + typename std::enable_if::value && has_traits::value, + ostream&>::type + operator<<(ostream& str, const T& obj) +{ + write_tuple_traits(str, obj._tls_fields_w()); + return str; +} + +// Struct reader without traits (enabled by macro) +template +inline typename std::enable_if::type +read_tuple(istream&, const std::tuple&) +{ +} + +template + inline + typename std::enable_if < I::type + read_tuple(istream& str, const std::tuple& t) +{ + str >> std::get(t); + read_tuple(str, t); +} + +template +inline + typename std::enable_if::value && !has_traits::value, + istream&>::type + operator>>(istream& str, T& obj) +{ + read_tuple(str, obj._tls_fields_r()); + return str; +} + +// Struct reader with traits (enabled by macro) +template +inline typename std::enable_if::type +read_tuple_traits(istream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + read_tuple_traits(istream& str, const std::tuple& t) +{ + std::tuple_element_t::decode(str, std::get(t)); + read_tuple_traits(str, t); +} + +template +inline + typename std::enable_if::value && has_traits::value, + istream&>::type + operator>>(istream& str, T& obj) +{ + read_tuple_traits(str, obj._tls_fields_r()); + return str; +} + +} // namespace mlspp::tls diff --git a/mlspp/lib/bytes/src/bytes.cpp b/mlspp/lib/bytes/src/bytes.cpp new file mode 100755 index 0000000000..634b9f9aad --- /dev/null +++ b/mlspp/lib/bytes/src/bytes.cpp @@ -0,0 +1,146 @@ +#include + +#include +#include +#include +#include + +namespace mlspp::bytes_ns { + +bool +bytes::operator==(const bytes& other) const +{ + return *this == other._data; +} + +bool +bytes::operator!=(const bytes& other) const +{ + return !(*this == other._data); +} + +bool +bytes::operator==(const std::vector& other) const +{ + const size_t size = other.size(); + if (_data.size() != size) { + return false; + } + + unsigned char diff = 0; + for (size_t i = 0; i < size; ++i) { + // Not sure why the linter thinks `diff` is signed + // NOLINTNEXTLINE(hicpp-signed-bitwise) + diff |= (_data.at(i) ^ other.at(i)); + } + return (diff == 0); +} + +bool +bytes::operator!=(const std::vector& other) const +{ + return !(*this == other); +} + +bytes& +bytes::operator+=(const bytes& other) +{ + // Not sure what the default argument is here + // NOLINTNEXTLINE(fuchsia-default-arguments) + _data.insert(end(), other.begin(), other.end()); + return *this; +} + +bytes +bytes::operator+(const bytes& rhs) const +{ + bytes out = *this; + out += rhs; + return out; +} + +bool +bytes::operator<(const bytes& rhs) const +{ + return _data < rhs._data; +} + +bytes +bytes::operator^(const bytes& rhs) const +{ + if (size() != rhs.size()) { + throw std::invalid_argument("XOR with unequal size"); + } + + bytes out = *this; + for (size_t i = 0; i < size(); ++i) { + out.at(i) ^= rhs.at(i); + } + return out; +} + +std::string +to_ascii(const bytes& data) +{ + return { data.begin(), data.end() }; +} + +bytes +from_ascii(const std::string& ascii) +{ + return std::vector(ascii.begin(), ascii.end()); +} + +std::string +to_hex(const bytes& data) +{ + std::stringstream hex(std::ios_base::out); + hex.flags(std::ios::hex); + for (const auto& byte : data) { + hex << std::setw(2) << std::setfill('0') << int(byte); + } + return hex.str(); +} + +bytes +from_hex(const std::string& hex) +{ + if (hex.length() % 2 == 1) { + throw std::invalid_argument("Odd-length hex string"); + } + + auto len = hex.length() / 2; + auto out = bytes(len); + for (size_t i = 0; i < len; i += 1) { + const std::string byte = hex.substr(2 * i, 2); + out.at(i) = static_cast(strtol(byte.c_str(), nullptr, 16)); + } + + return out; +} + +std::ostream& +operator<<(std::ostream& out, const bytes& data) +{ + // Adjust this threshold to make output more compact + const size_t threshold = 0xffff; + if (data.size() < threshold) { + return out << to_hex(data); + } + + return out << to_hex(data.slice(0, threshold)) << "..."; +} + +bool +operator==(const std::vector& lhs, const bytes_ns::bytes& rhs) +{ + return rhs == lhs; +} + +bool +operator!=(const std::vector& lhs, const bytes_ns::bytes& rhs) +{ + return rhs != lhs; +} + +} // namespace mlspp::bytes_ns diff --git a/mlspp/lib/hpke/CMakeLists.txt b/mlspp/lib/hpke/CMakeLists.txt new file mode 100755 index 0000000000..b8e5ac79e0 --- /dev/null +++ b/mlspp/lib/hpke/CMakeLists.txt @@ -0,0 +1,57 @@ +set(CURRENT_LIB_NAME hpke) + +### +### Library Config +### + +file(GLOB_RECURSE LIB_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +# -Werror=dangling-reference + +add_library(${CURRENT_LIB_NAME} STATIC ${LIB_HEADERS} ${LIB_SOURCES}) +add_dependencies(${CURRENT_LIB_NAME} bytes tls_syntax) +target_include_directories(${CURRENT_LIB_NAME} + PRIVATE + "${JSON_INCLUDE_INTERFACE}") + +target_link_libraries(${CURRENT_LIB_NAME} + PUBLIC + bytes tls_syntax +) + +target_include_directories(${CURRENT_LIB_NAME} + PUBLIC + $ + $ + $ + PRIVATE + ${OPENSSL_INCLUDE_DIR} +) + +# Private statically linked dependencies +target_link_libraries(${CURRENT_LIB_NAME} PRIVATE + mlspp + mls_vectors + bytes + tls_syntax +) + +target_compile_options( + "${CURRENT_LIB_NAME}" + PUBLIC + "$<$:/bigobj;/Zc:preprocessor>" + PRIVATE + "$<$:$<$:/sdl;/Od;/DEBUG;/MP;/DFD_SETSIZE=1024>>" + "$<$:$<$:/O2;/Oi;/Oy;/GL;/Gy;/sdl;/MP;/DFD_SETSIZE=1024>>" + "$<$:$<$:-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" + "$<$:$<$:-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" + "${AVX_FLAG}" +) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/bytes/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/hpke/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/mls_vectors/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/tls_syntax/include") +# For nlohmann/json.hpp +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") diff --git a/mlspp/lib/hpke/include/hpke/base64.h b/mlspp/lib/hpke/include/hpke/base64.h new file mode 100755 index 0000000000..44ab7a5a09 --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/base64.h @@ -0,0 +1,20 @@ +#pragma once + +#include +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +std::string +to_base64(const bytes& data); + +std::string +to_base64url(const bytes& data); + +bytes +from_base64(const std::string& enc); + +bytes +from_base64url(const std::string& enc); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/certificate.h b/mlspp/lib/hpke/include/hpke/certificate.h new file mode 100755 index 0000000000..752c5f417b --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/certificate.h @@ -0,0 +1,75 @@ +#pragma once +#include +#include + +#include +#include +#include +#include + +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +struct Certificate +{ +private: + struct ParsedCertificate; + std::unique_ptr parsed_cert; + +public: + struct NameType + { + static const int organization; + static const int common_name; + static const int organizational_unit; + static const int country; + static const int serial_number; + static const int state_or_province_name; + }; + + using ParsedName = std::map; + + // Certificate Expiration Status + enum struct ExpirationStatus + { + inactive, // now < notBefore + active, // notBefore < now < notAfter + expired, // notAfter < now + }; + + explicit Certificate(const bytes& der); + explicit Certificate(std::unique_ptr&& parsed_cert_in); + Certificate() = delete; + Certificate(const Certificate& other); + ~Certificate(); + + static std::vector parse_pem(const bytes& pem); + + bool valid_from(const Certificate& parent) const; + + // Accessors for parsed certificate elements + uint64_t issuer_hash() const; + uint64_t subject_hash() const; + ParsedName issuer() const; + ParsedName subject() const; + bool is_ca() const; + ExpirationStatus expiration_status() const; + std::optional subject_key_id() const; + std::optional authority_key_id() const; + std::vector email_addresses() const; + std::vector dns_names() const; + bytes hash() const; + std::chrono::system_clock::time_point not_before() const; + std::chrono::system_clock::time_point not_after() const; + Signature::ID public_key_algorithm() const; + Signature::ID signature_algorithm() const; + + const std::unique_ptr public_key; + const bytes raw; +}; + +bool +operator==(const Certificate& lhs, const Certificate& rhs); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/digest.h b/mlspp/lib/hpke/include/hpke/digest.h new file mode 100755 index 0000000000..025669133e --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/digest.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include + +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +struct Digest +{ + enum struct ID + { + SHA256, + SHA384, + SHA512, + }; + + template + static const Digest& get(); + + const ID id; + + bytes hash(const bytes& data) const; + bytes hmac(const bytes& key, const bytes& data) const; + + const size_t hash_size; + +private: + explicit Digest(ID id); + + bytes hmac_for_hkdf_extract(const bytes& key, const bytes& data) const; + friend struct HKDF; +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/hpke.h b/mlspp/lib/hpke/include/hpke/hpke.h new file mode 100755 index 0000000000..4cf8c00a28 --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/hpke.h @@ -0,0 +1,253 @@ +#pragma once + +#include +#include + +#include +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +struct KEM +{ + enum struct ID : uint16_t + { + DHKEM_P256_SHA256 = 0x0010, + DHKEM_P384_SHA384 = 0x0011, + DHKEM_P521_SHA512 = 0x0012, + DHKEM_X25519_SHA256 = 0x0020, +#if !defined(WITH_BORINGSSL) + DHKEM_X448_SHA512 = 0x0021, +#endif + }; + + template + static const KEM& get(); + + virtual ~KEM() = default; + + struct PublicKey + { + virtual ~PublicKey() = default; + }; + + struct PrivateKey + { + virtual ~PrivateKey() = default; + virtual std::unique_ptr public_key() const = 0; + }; + + const ID id; + const size_t secret_size; + const size_t enc_size; + const size_t pk_size; + const size_t sk_size; + + virtual std::unique_ptr generate_key_pair() const = 0; + virtual std::unique_ptr derive_key_pair( + const bytes& ikm) const = 0; + + virtual bytes serialize(const PublicKey& pk) const = 0; + virtual std::unique_ptr deserialize(const bytes& enc) const = 0; + + virtual bytes serialize_private(const PrivateKey& sk) const; + virtual std::unique_ptr deserialize_private( + const bytes& skm) const; + + // (shared_secret, enc) + virtual std::pair encap(const PublicKey& pkR) const = 0; + virtual bytes decap(const bytes& enc, const PrivateKey& skR) const = 0; + + // (shared_secret, enc) + virtual std::pair auth_encap(const PublicKey& pkR, + const PrivateKey& skS) const; + virtual bytes auth_decap(const bytes& enc, + const PublicKey& pkS, + const PrivateKey& skR) const; + +protected: + KEM(ID id_in, + size_t secret_size_in, + size_t enc_size_in, + size_t pk_size_in, + size_t sk_size_in); +}; + +struct KDF +{ + enum struct ID : uint16_t + { + HKDF_SHA256 = 0x0001, + HKDF_SHA384 = 0x0002, + HKDF_SHA512 = 0x0003, + }; + + template + static const KDF& get(); + + virtual ~KDF() = default; + + const ID id; + const size_t hash_size; + + virtual bytes extract(const bytes& salt, const bytes& ikm) const = 0; + virtual bytes expand(const bytes& prk, + const bytes& info, + size_t size) const = 0; + + bytes labeled_extract(const bytes& suite_id, + const bytes& salt, + const bytes& label, + const bytes& ikm) const; + bytes labeled_expand(const bytes& suite_id, + const bytes& prk, + const bytes& label, + const bytes& info, + size_t size) const; + +protected: + KDF(ID id_in, size_t hash_size_in); +}; + +struct AEAD +{ + enum struct ID : uint16_t + { + AES_128_GCM = 0x0001, + AES_256_GCM = 0x0002, + CHACHA20_POLY1305 = 0x0003, + + // Reserved identifier for pseudo-AEAD on contexts that only allow export + export_only = 0xffff, + }; + + template + static const AEAD& get(); + + virtual ~AEAD() = default; + + const ID id; + const size_t key_size; + const size_t nonce_size; + + virtual bytes seal(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& pt) const = 0; + virtual std::optional open(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& ct) const = 0; + +protected: + AEAD(ID id_in, size_t key_size_in, size_t nonce_size_in); +}; + +struct Context +{ + bytes do_export(const bytes& exporter_context, size_t size) const; + +protected: + bytes suite; + bytes key; + bytes nonce; + bytes exporter_secret; + const KDF& kdf; + const AEAD& aead; + + bytes current_nonce() const; + void increment_seq(); + +private: + uint64_t seq; + + Context(bytes suite_in, + bytes key_in, + bytes nonce_in, + bytes exporter_secret_in, + const KDF& kdf_in, + const AEAD& aead_in); + + friend struct HPKE; + friend struct HPKETest; + friend bool operator==(const Context& lhs, const Context& rhs); +}; + +struct SenderContext : public Context +{ + SenderContext(Context&& c); + bytes seal(const bytes& aad, const bytes& pt); +}; + +struct ReceiverContext : public Context +{ + ReceiverContext(Context&& c); + std::optional open(const bytes& aad, const bytes& ct); +}; + +struct HPKE +{ + enum struct Mode : uint8_t + { + base = 0, + psk = 1, + auth = 2, + auth_psk = 3, + }; + + HPKE(KEM::ID kem_id, KDF::ID kdf_id, AEAD::ID aead_id); + + using SenderInfo = std::pair; + + SenderInfo setup_base_s(const KEM::PublicKey& pkR, const bytes& info) const; + ReceiverContext setup_base_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info) const; + + SenderInfo setup_psk_s(const KEM::PublicKey& pkR, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const; + ReceiverContext setup_psk_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const; + + SenderInfo setup_auth_s(const KEM::PublicKey& pkR, + const bytes& info, + const KEM::PrivateKey& skS) const; + ReceiverContext setup_auth_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const KEM::PublicKey& pkS) const; + + SenderInfo setup_auth_psk_s(const KEM::PublicKey& pkR, + const bytes& info, + const bytes& psk, + const bytes& psk_id, + const KEM::PrivateKey& skS) const; + ReceiverContext setup_auth_psk_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const bytes& psk, + const bytes& psk_id, + const KEM::PublicKey& pkS) const; + + bytes suite; + const KEM& kem; + const KDF& kdf; + const AEAD& aead; + +private: + static bool verify_psk_inputs(Mode mode, + const bytes& psk, + const bytes& psk_id); + Context key_schedule(Mode mode, + const bytes& shared_secret, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const; +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/random.h b/mlspp/lib/hpke/include/hpke/random.h new file mode 100755 index 0000000000..ad344e659c --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/random.h @@ -0,0 +1,11 @@ +#pragma once + +#include +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +bytes +random_bytes(size_t size); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/signature.h b/mlspp/lib/hpke/include/hpke/signature.h new file mode 100755 index 0000000000..8e5985a840 --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/signature.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#include +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +struct Signature +{ + enum struct ID + { + P256_SHA256, + P384_SHA384, + P521_SHA512, + Ed25519, +#if !defined(WITH_BORINGSSL) + Ed448, +#endif + RSA_SHA256, + RSA_SHA384, + RSA_SHA512, + }; + + template + static const Signature& get(); + + virtual ~Signature() = default; + + struct PublicKey + { + virtual ~PublicKey() = default; + }; + + struct PrivateKey + { + virtual ~PrivateKey() = default; + virtual std::unique_ptr public_key() const = 0; + }; + + const ID id; + + virtual std::unique_ptr generate_key_pair() const = 0; + virtual std::unique_ptr derive_key_pair( + const bytes& ikm) const = 0; + + virtual bytes serialize(const PublicKey& pk) const = 0; + virtual std::unique_ptr deserialize(const bytes& enc) const = 0; + + virtual bytes serialize_private(const PrivateKey& sk) const = 0; + virtual std::unique_ptr deserialize_private( + const bytes& skm) const = 0; + + struct PrivateJWK + { + const Signature& sig; + std::optional key_id; + std::unique_ptr key; + }; + static PrivateJWK parse_jwk_private(const std::string& jwk_json); + + struct PublicJWK + { + const Signature& sig; + std::optional key_id; + std::unique_ptr key; + }; + static PublicJWK parse_jwk(const std::string& jwk_json); + + virtual std::unique_ptr import_jwk_private( + const std::string& jwk_json) const = 0; + virtual std::unique_ptr import_jwk( + const std::string& jwk_json) const = 0; + virtual std::string export_jwk_private(const PrivateKey& env) const = 0; + virtual std::string export_jwk(const PublicKey& env) const = 0; + + virtual bytes sign(const bytes& data, const PrivateKey& sk) const = 0; + virtual bool verify(const bytes& data, + const bytes& sig, + const PublicKey& pk) const = 0; + + static std::unique_ptr generate_rsa(size_t bits); + +protected: + Signature(ID id_in); +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/include/hpke/userinfo_vc.h b/mlspp/lib/hpke/include/hpke/userinfo_vc.h new file mode 100755 index 0000000000..9f3cae27f4 --- /dev/null +++ b/mlspp/lib/hpke/include/hpke/userinfo_vc.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include + +#include +#include +#include +#include + +using namespace mlspp::bytes_ns; + +namespace mlspp::hpke { + +struct UserInfoClaimsAddress +{ + std::optional formatted; + std::optional street_address; + std::optional locality; + std::optional region; + std::optional postal_code; + std::optional country; +}; + +struct UserInfoClaims +{ + + std::optional sub; + std::optional name; + std::optional given_name; + std::optional family_name; + std::optional middle_name; + std::optional nickname; + std::optional preferred_username; + std::optional profile; + std::optional picture; + std::optional website; + std::optional email; + std::optional email_verified; + std::optional gender; + std::optional birthdate; + std::optional zoneinfo; + std::optional locale; + std::optional phone_number; + std::optional phone_number_verified; + std::optional address; + std::optional updated_at; + + static UserInfoClaims from_json(const std::string& cred_subject); +}; + +struct UserInfoVC +{ +private: + struct ParsedCredential; + std::shared_ptr parsed_cred; + +public: + explicit UserInfoVC(std::string jwt); + UserInfoVC() = default; + UserInfoVC(const UserInfoVC& other) = default; + ~UserInfoVC() = default; + UserInfoVC& operator=(const UserInfoVC& other) = default; + UserInfoVC& operator=(UserInfoVC&& other) = default; + + const Signature& signature_algorithm() const; + std::string issuer() const; + std::optional key_id() const; + std::chrono::system_clock::time_point not_before() const; + std::chrono::system_clock::time_point not_after() const; + const std::string& raw_credential() const; + const UserInfoClaims& subject() const; + const Signature::PublicJWK& public_key() const; + + bool valid_from(const Signature::PublicKey& issuer_key) const; + + std::string raw; +}; + +bool +operator==(const UserInfoVC& lhs, const UserInfoVC& rhs); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/aead_cipher.cpp b/mlspp/lib/hpke/src/aead_cipher.cpp new file mode 100755 index 0000000000..b200647789 --- /dev/null +++ b/mlspp/lib/hpke/src/aead_cipher.cpp @@ -0,0 +1,321 @@ +#include "aead_cipher.h" +#include "openssl_common.h" + +#include + +#if WITH_BORINGSSL +#include +#endif + +namespace mlspp::hpke { + +/// +/// ExportOnlyCipher +/// +bytes +ExportOnlyCipher::seal(const bytes& /* key */, + const bytes& /* nonce */, + const bytes& /* aad */, + const bytes& /* pt */) const +{ + throw std::runtime_error("seal() on export-only context"); +} + +std::optional +ExportOnlyCipher::open(const bytes& /* key */, + const bytes& /* nonce */, + const bytes& /* aad */, + const bytes& /* ct */) const +{ + throw std::runtime_error("open() on export-only context"); +} + +ExportOnlyCipher::ExportOnlyCipher() + : AEAD(AEAD::ID::export_only, 0, 0) +{ +} + +/// +/// AEADCipher +/// +AEADCipher +make_aead(AEAD::ID cipher_in) +{ + return { cipher_in }; +} + +template<> +const AEADCipher& +AEADCipher::get() +{ + static const auto instance = make_aead(AEAD::ID::AES_128_GCM); + return instance; +} + +template<> +const AEADCipher& +AEADCipher::get() +{ + static const auto instance = make_aead(AEAD::ID::AES_256_GCM); + return instance; +} + +template<> +const AEADCipher& +AEADCipher::get() +{ + static const auto instance = make_aead(AEAD::ID::CHACHA20_POLY1305); + return instance; +} + +static size_t +cipher_key_size(AEAD::ID cipher) +{ + switch (cipher) { + case AEAD::ID::AES_128_GCM: + return 16; + + case AEAD::ID::AES_256_GCM: + case AEAD::ID::CHACHA20_POLY1305: + return 32; + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +static size_t +cipher_nonce_size(AEAD::ID cipher) +{ + switch (cipher) { + case AEAD::ID::AES_128_GCM: + case AEAD::ID::AES_256_GCM: + case AEAD::ID::CHACHA20_POLY1305: + return 12; + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +static size_t +cipher_tag_size(AEAD::ID cipher) +{ + switch (cipher) { + case AEAD::ID::AES_128_GCM: + case AEAD::ID::AES_256_GCM: + case AEAD::ID::CHACHA20_POLY1305: + return 16; + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +#if WITH_BORINGSSL +static const EVP_AEAD* +boringssl_cipher(AEAD::ID cipher) +{ + switch (cipher) { + case AEAD::ID::AES_128_GCM: + return EVP_aead_aes_128_gcm(); + + case AEAD::ID::AES_256_GCM: + return EVP_aead_aes_256_gcm(); + + case AEAD::ID::CHACHA20_POLY1305: + return EVP_aead_chacha20_poly1305(); + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} +#else +static const EVP_CIPHER* +openssl_cipher(AEAD::ID cipher) +{ + switch (cipher) { + case AEAD::ID::AES_128_GCM: + return EVP_aes_128_gcm(); + + case AEAD::ID::AES_256_GCM: + return EVP_aes_256_gcm(); + + case AEAD::ID::CHACHA20_POLY1305: + return EVP_chacha20_poly1305(); + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} +#endif // WITH_BORINGSSL + +AEADCipher::AEADCipher(AEAD::ID id_in) + : AEAD(id_in, cipher_key_size(id_in), cipher_nonce_size(id_in)) + , tag_size(cipher_tag_size(id)) +{ +} + +bytes +AEADCipher::seal(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& pt) const +{ +#if WITH_BORINGSSL + auto ctx = make_typed_unique( + EVP_AEAD_CTX_new(boringssl_cipher(id), key.data(), key.size(), tag_size)); + if (ctx == nullptr) { + throw openssl_error(); + } + + auto ct = bytes(pt.size() + tag_size); + auto out_len = ct.size(); + if (1 != EVP_AEAD_CTX_seal(ctx.get(), + ct.data(), + &out_len, + ct.size(), + nonce.data(), + nonce.size(), + pt.data(), + pt.size(), + aad.data(), + aad.size())) { + throw openssl_error(); + } + + return ct; +#else + auto ctx = make_typed_unique(EVP_CIPHER_CTX_new()); + if (ctx == nullptr) { + throw openssl_error(); + } + + const auto* cipher = openssl_cipher(id); + if (1 != EVP_EncryptInit(ctx.get(), cipher, key.data(), nonce.data())) { + throw openssl_error(); + } + + int outlen = 0; + if (!aad.empty()) { + if (1 != EVP_EncryptUpdate(ctx.get(), + nullptr, + &outlen, + aad.data(), + static_cast(aad.size()))) { + throw openssl_error(); + } + } + + bytes ct(pt.size()); + if (1 != EVP_EncryptUpdate(ctx.get(), + ct.data(), + &outlen, + pt.data(), + static_cast(pt.size()))) { + throw openssl_error(); + } + + // Providing nullptr as an argument is safe here because this + // function never writes with GCM; it only computes the tag + if (1 != EVP_EncryptFinal(ctx.get(), nullptr, &outlen)) { + throw openssl_error(); + } + + bytes tag(tag_size); + if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), + EVP_CTRL_GCM_GET_TAG, + static_cast(tag_size), + tag.data())) { + throw openssl_error(); + } + + ct += tag; + return ct; +#endif // WITH_BORINGSSL +} + +std::optional +AEADCipher::open(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& ct) const +{ + if (ct.size() < tag_size) { + throw std::runtime_error("AEAD ciphertext smaller than tag size"); + } + +#if WITH_BORINGSSL + auto ctx = make_typed_unique(EVP_AEAD_CTX_new( + boringssl_cipher(id), key.data(), key.size(), cipher_tag_size(id))); + if (ctx == nullptr) { + throw openssl_error(); + } + + auto pt = bytes(ct.size() - tag_size); + auto out_len = pt.size(); + if (1 != EVP_AEAD_CTX_open(ctx.get(), + pt.data(), + &out_len, + pt.size(), + nonce.data(), + nonce.size(), + ct.data(), + ct.size(), + aad.data(), + aad.size())) { + throw openssl_error(); + } + + return pt; +#else + auto ctx = make_typed_unique(EVP_CIPHER_CTX_new()); + if (ctx == nullptr) { + throw openssl_error(); + } + + const auto* cipher = openssl_cipher(id); + if (1 != EVP_DecryptInit(ctx.get(), cipher, key.data(), nonce.data())) { + throw openssl_error(); + } + + auto inner_ct_size = ct.size() - tag_size; + auto tag = ct.slice(inner_ct_size, ct.size()); + if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), + EVP_CTRL_GCM_SET_TAG, + static_cast(tag_size), + tag.data())) { + throw openssl_error(); + } + + int out_size = 0; + if (!aad.empty()) { + if (1 != EVP_DecryptUpdate(ctx.get(), + nullptr, + &out_size, + aad.data(), + static_cast(aad.size()))) { + throw openssl_error(); + } + } + + bytes pt(inner_ct_size); + if (1 != EVP_DecryptUpdate(ctx.get(), + pt.data(), + &out_size, + ct.data(), + static_cast(inner_ct_size))) { + throw openssl_error(); + } + + // Providing nullptr as an argument is safe here because this + // function never writes with GCM; it only verifies the tag + if (1 != EVP_DecryptFinal(ctx.get(), nullptr, &out_size)) { + throw std::runtime_error("AEAD authentication failure"); + } + + return pt; +#endif // WITH_BORINGSSL +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/aead_cipher.h b/mlspp/lib/hpke/src/aead_cipher.h new file mode 100755 index 0000000000..32a36964fc --- /dev/null +++ b/mlspp/lib/hpke/src/aead_cipher.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +namespace mlspp::hpke { + +struct ExportOnlyCipher : public AEAD +{ + ExportOnlyCipher(); + ~ExportOnlyCipher() override = default; + + bytes seal(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& pt) const override; + std::optional open(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& ct) const override; +}; + +struct AEADCipher : public AEAD +{ + template + static const AEADCipher& get(); + + ~AEADCipher() override = default; + + bytes seal(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& pt) const override; + std::optional open(const bytes& key, + const bytes& nonce, + const bytes& aad, + const bytes& ct) const override; + +private: + const size_t tag_size; + + AEADCipher(AEAD::ID id_in); + friend AEADCipher make_aead(AEAD::ID cipher_in); +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/base64.cpp b/mlspp/lib/hpke/src/base64.cpp new file mode 100755 index 0000000000..7db48df75b --- /dev/null +++ b/mlspp/lib/hpke/src/base64.cpp @@ -0,0 +1,105 @@ +#include + +#include "openssl_common.h" + +#include +#include +#include + +namespace mlspp::hpke { + +std::string +to_base64(const bytes& data) +{ + if (data.empty()) { + return ""; + } + +#if WITH_BORINGSSL + const auto data_size = data.size(); +#else + const auto data_size = static_cast(data.size()); +#endif + + // base64 encoding produces 4 characters for every 3 input bytes (rounded up) + const auto out_size = (data_size + 2) / 3 * 4; + auto out = bytes(out_size + 1); // NUL terminator + + const auto result = EVP_EncodeBlock(out.data(), data.data(), data_size); + if (result != out_size) { + throw openssl_error(); + } + + out.resize(out.size() - 1); // strip NUL terminator + return to_ascii(out); +} + +std::string +to_base64url(const bytes& data) +{ + if (data.empty()) { + return ""; + } + + auto encoded = to_base64(data); + + auto pad_start = encoded.find_first_of('='); + if (pad_start != std::string::npos) { + encoded = encoded.substr(0, pad_start); + } + + std::replace(encoded.begin(), encoded.end(), '+', '-'); + std::replace(encoded.begin(), encoded.end(), '/', '_'); + + return encoded; +} + +bytes +from_base64(const std::string& enc) +{ + if (enc.length() == 0) { + return {}; + } + + if (enc.length() % 4 != 0) { + throw std::runtime_error("Base64 length is not divisible by 4"); + } + + const auto in = from_ascii(enc); + const auto in_size = static_cast(in.size()); + const auto out_size = in_size / 4 * 3; + auto out = bytes(out_size); + + const auto result = EVP_DecodeBlock(out.data(), in.data(), in_size); + if (result != out_size) { + throw openssl_error(); + } + + if (enc.substr(enc.length() - 2, enc.length()) == "==") { + out.resize(out.size() - 2); + } else if (enc.substr(enc.length() - 1, enc.length()) == "=") { + out.resize(out.size() - 1); + } + + return out; +} + +bytes +from_base64url(const std::string& enc) +{ + if (enc.empty()) { + return {}; + } + + auto enc_copy = enc; + std::replace(enc_copy.begin(), enc_copy.end(), '-', '+'); + std::replace(enc_copy.begin(), enc_copy.end(), '_', '/'); + + while (enc_copy.length() % 4 != 0) { + enc_copy += "="; + } + + return from_base64(enc_copy); +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/certificate.cpp b/mlspp/lib/hpke/src/certificate.cpp new file mode 100755 index 0000000000..f4b72dee37 --- /dev/null +++ b/mlspp/lib/hpke/src/certificate.cpp @@ -0,0 +1,539 @@ +#include "group.h" +#include "openssl_common.h" +#include "rsa.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mlspp::hpke { +/// +/// Utility functions +/// + +static std::optional +asn1_octet_string_to_bytes(const ASN1_OCTET_STRING* octets) +{ + if (octets == nullptr) { + return std::nullopt; + } + const auto* ptr = ASN1_STRING_get0_data(octets); + const auto len = ASN1_STRING_length(octets); + // NOLINTNEXTLINE (cppcoreguidelines-pro-bounds-pointer-arithmetic) + return std::vector(ptr, ptr + len); +} + +static std::string +asn1_string_to_std_string(const ASN1_STRING* asn1_string) +{ + const auto* data = ASN1_STRING_get0_data(asn1_string); + const auto data_size = static_cast(ASN1_STRING_length(asn1_string)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto str = std::string(reinterpret_cast(data)); + if (str.size() != data_size) { + throw std::runtime_error("Malformed ASN.1 string"); + } + return str; +} + +static std::chrono::system_clock::time_point +asn1_time_to_chrono(const ASN1_TIME* asn1_time) +{ + auto epoch_chrono = std::chrono::system_clock::time_point(); + auto epoch_time_t = std::chrono::system_clock::to_time_t(epoch_chrono); + auto epoch_asn1 = make_typed_unique(ASN1_TIME_set(nullptr, epoch_time_t)); + if (!epoch_asn1) { + throw openssl_error(); + } + + auto secs = int(0); + auto days = int(0); + if (ASN1_TIME_diff(&days, &secs, epoch_asn1.get(), asn1_time) != 1) { + throw openssl_error(); + } + + auto delta = std::chrono::seconds(secs) + std::chrono::hours(24 * days); + return std::chrono::system_clock::time_point(delta); +} + +/// +/// ParsedCertificate +/// + +const int Certificate::NameType::organization = NID_organizationName; +const int Certificate::NameType::common_name = NID_commonName; +const int Certificate::NameType::organizational_unit = + NID_organizationalUnitName; +const int Certificate::NameType::country = NID_countryName; +const int Certificate::NameType::serial_number = NID_serialNumber; +const int Certificate::NameType::state_or_province_name = + NID_stateOrProvinceName; + +struct RFC822Name +{ + std::string value; +}; + +struct DNSName +{ + std::string value; +}; + +using GeneralName = tls::var::variant; + +struct Certificate::ParsedCertificate +{ + + static std::unique_ptr parse(const bytes& der) + { + const auto* buf = der.data(); + auto cert = + make_typed_unique(d2i_X509(nullptr, &buf, static_cast(der.size()))); + if (cert == nullptr) { + throw openssl_error(); + } + + return std::make_unique(cert.release()); + } + + static bytes compute_digest(const X509* cert) + { + const auto* md = EVP_sha256(); + auto digest = bytes(EVP_MD_size(md)); + unsigned int out_size = 0; + if (1 != X509_digest(cert, md, digest.data(), &out_size)) { + throw openssl_error(); + } + return digest; + } + + // Note: This method does not implement total general name parsing. + // Duplicate entries are not supported; if they are present, the last one + // presented by OpenSSL is chosen. + static ParsedName parse_names(const X509_NAME* x509_name) + { + if (x509_name == nullptr) { + throw openssl_error(); + } + + ParsedName parsed_name; + + for (int i = X509_NAME_entry_count(x509_name) - 1; i >= 0; i--) { + auto* entry = X509_NAME_get_entry(x509_name, i); + if (entry == nullptr) { + continue; + } + + auto* oid = X509_NAME_ENTRY_get_object(entry); + auto* asn_str = X509_NAME_ENTRY_get_data(entry); + if (oid == nullptr || asn_str == nullptr) { + continue; + } + + const int nid = OBJ_obj2nid(oid); + const std::string parsed_value = asn1_string_to_std_string(asn_str); + parsed_name[nid] = parsed_value; + } + + return parsed_name; + } + + // Parse Subject Key Identifier Extension + static std::optional parse_skid(X509* cert) + { + return asn1_octet_string_to_bytes(X509_get0_subject_key_id(cert)); + } + + // Parse Authority Key Identifier + static std::optional parse_akid(X509* cert) + { + return asn1_octet_string_to_bytes(X509_get0_authority_key_id(cert)); + } + + static std::vector parse_san(X509* cert) + { + std::vector names; + +#ifdef WITH_BORINGSSL + using san_names_nb_t = size_t; +#else + using san_names_nb_t = int; +#endif + + san_names_nb_t san_names_nb = 0; + + auto* ext_ptr = + X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto* san_ptr = reinterpret_cast(ext_ptr); + const auto san_names = make_typed_unique(san_ptr); + san_names_nb = sk_GENERAL_NAME_num(san_names.get()); + + // Check each name within the extension + for (san_names_nb_t i = 0; i < san_names_nb; i++) { + auto* current_name = sk_GENERAL_NAME_value(san_names.get(), i); + if (current_name->type == GEN_DNS) { + const auto dns_name = + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + asn1_string_to_std_string(current_name->d.dNSName); + names.emplace_back(DNSName{ dns_name }); + } else if (current_name->type == GEN_EMAIL) { + const auto email = + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access + asn1_string_to_std_string(current_name->d.rfc822Name); + names.emplace_back(RFC822Name{ email }); + } + } + + return names; + } + + explicit ParsedCertificate(X509* x509_in) + : x509(x509_in, typed_delete) + , pub_key_id(public_key_algorithm(x509.get())) + , sig_algo(signature_algorithm(x509.get())) + , issuer_hash(X509_issuer_name_hash(x509.get())) + , subject_hash(X509_subject_name_hash(x509.get())) + , issuer(parse_names(X509_get_issuer_name(x509.get()))) + , subject(parse_names(X509_get_subject_name(x509.get()))) + , subject_key_id(parse_skid(x509.get())) + , authority_key_id(parse_akid(x509.get())) + , sub_alt_names(parse_san(x509.get())) + , is_ca(X509_check_ca(x509.get()) != 0) + , hash(compute_digest(x509.get())) + , not_before(asn1_time_to_chrono(X509_get0_notBefore(x509.get()))) + , not_after(asn1_time_to_chrono(X509_get0_notAfter(x509.get()))) + { + } + + ParsedCertificate(const ParsedCertificate& other) + : x509(nullptr, typed_delete) + , pub_key_id(public_key_algorithm(other.x509.get())) + , sig_algo(signature_algorithm(other.x509.get())) + , issuer_hash(other.issuer_hash) + , subject_hash(other.subject_hash) + , issuer(other.issuer) + , subject(other.subject) + , subject_key_id(other.subject_key_id) + , authority_key_id(other.authority_key_id) + , sub_alt_names(other.sub_alt_names) + , is_ca(other.is_ca) + , hash(other.hash) + , not_before(other.not_before) + , not_after(other.not_after) + { + if (1 != X509_up_ref(other.x509.get())) { + throw openssl_error(); + } + x509.reset(other.x509.get()); + } + + static Signature::ID public_key_algorithm(X509* x509) + { +#if WITH_BORINGSSL + const auto pub = make_typed_unique(X509_get_pubkey(x509)); + const auto* pub_ptr = pub.get(); +#else + const auto* pub_ptr = X509_get0_pubkey(x509); +#endif + + switch (EVP_PKEY_base_id(pub_ptr)) { + case EVP_PKEY_ED25519: + return Signature::ID::Ed25519; +#if !defined(WITH_BORINGSSL) + case EVP_PKEY_ED448: + return Signature::ID::Ed448; +#endif + case EVP_PKEY_EC: { + auto key_size = EVP_PKEY_bits(pub_ptr); + switch (key_size) { + case 256: + return Signature::ID::P256_SHA256; + case 384: + return Signature::ID::P384_SHA384; + case 521: + return Signature::ID::P521_SHA512; + default: + throw std::runtime_error("Unknown curve"); + } + } + case EVP_PKEY_RSA: + // RSA public keys are not specific to an algorithm + return Signature::ID::RSA_SHA256; + default: + break; + } + throw std::runtime_error("Unsupported public key algorithm"); + } + + static Signature::ID signature_algorithm(X509* cert) + { + auto nid = X509_get_signature_nid(cert); + switch (nid) { + case EVP_PKEY_ED25519: + return Signature::ID::Ed25519; +#if !defined(WITH_BORINGSSL) + case EVP_PKEY_ED448: + return Signature::ID::Ed448; +#endif + case NID_ecdsa_with_SHA256: + return Signature::ID::P256_SHA256; + case NID_ecdsa_with_SHA384: + return Signature::ID::P384_SHA384; + case NID_ecdsa_with_SHA512: + return Signature::ID::P521_SHA512; + case NID_sha1WithRSAEncryption: + // We fall through to SHA256 for SHA1 because we do not implement SHA-1. + case NID_sha256WithRSAEncryption: + return Signature::ID::RSA_SHA256; + case NID_sha384WithRSAEncryption: + return Signature::ID::RSA_SHA384; + case NID_sha512WithRSAEncryption: + return Signature::ID::RSA_SHA512; + default: + break; + } + + throw std::runtime_error("Unsupported signature algorithm"); + } + + typed_unique_ptr public_key() const + { + return make_typed_unique(X509_get_pubkey(x509.get())); + } + + Certificate::ExpirationStatus expiration_status() const + { + auto now = std::chrono::system_clock::now(); + + if (now < not_before) { + return Certificate::ExpirationStatus::inactive; + } + + if (now > not_after) { + return Certificate::ExpirationStatus::expired; + } + + return Certificate::ExpirationStatus::active; + } + + bytes raw() const + { + auto out = bytes(i2d_X509(x509.get(), nullptr)); + auto* ptr = out.data(); + i2d_X509(x509.get(), &ptr); + return out; + } + + typed_unique_ptr x509; + const Signature::ID pub_key_id; + const Signature::ID sig_algo; + const uint64_t issuer_hash; + const uint64_t subject_hash; + const ParsedName issuer; + const ParsedName subject; + const std::optional subject_key_id; + const std::optional authority_key_id; + const std::vector sub_alt_names; + const bool is_ca; + const bytes hash; + const std::chrono::system_clock::time_point not_before; + const std::chrono::system_clock::time_point not_after; +}; + +/// +/// Certificate +/// + +static std::unique_ptr +signature_key(EVP_PKEY* pkey) +{ + switch (EVP_PKEY_base_id(pkey)) { + case EVP_PKEY_RSA: + return std::make_unique(pkey); + + case EVP_PKEY_ED448: + case EVP_PKEY_ED25519: + case EVP_PKEY_EC: + return std::make_unique(pkey); + + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +Certificate::Certificate(std::unique_ptr&& parsed_cert_in) + : parsed_cert(std::move(parsed_cert_in)) + , public_key(signature_key(parsed_cert->public_key().release())) + , raw(parsed_cert->raw()) +{ +} + +Certificate::Certificate(const bytes& der) + : parsed_cert(ParsedCertificate::parse(der)) + , public_key(signature_key(parsed_cert->public_key().release())) + , raw(der) +{ +} + +Certificate::Certificate(const Certificate& other) + : parsed_cert(std::make_unique(*other.parsed_cert)) + , public_key(signature_key(parsed_cert->public_key().release())) + , raw(other.raw) +{ +} + +Certificate::~Certificate() = default; + +std::vector +Certificate::parse_pem(const bytes& pem) +{ + auto size_int = static_cast(pem.size()); + auto bio = make_typed_unique(BIO_new_mem_buf(pem.data(), size_int)); + if (!bio) { + throw openssl_error(); + } + + auto certs = std::vector(); + while (true) { + auto x509 = make_typed_unique( + PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); + if (!x509) { + // NOLINTNEXTLINE(hicpp-signed-bitwise) + auto err = ERR_GET_REASON(ERR_peek_last_error()); + if (err == PEM_R_NO_START_LINE) { + // No more objects to read + break; + } + + throw openssl_error(); + } + + auto parsed = std::make_unique(x509.release()); + certs.emplace_back(std::move(parsed)); + } + + return certs; +} + +bool +Certificate::valid_from(const Certificate& parent) const +{ + auto pub = parent.parsed_cert->public_key(); + return (1 == X509_verify(parsed_cert->x509.get(), pub.get())); +} + +uint64_t +Certificate::issuer_hash() const +{ + return parsed_cert->issuer_hash; +} + +uint64_t +Certificate::subject_hash() const +{ + return parsed_cert->subject_hash; +} + +Certificate::ParsedName +Certificate::subject() const +{ + return parsed_cert->subject; +} + +Certificate::ParsedName +Certificate::issuer() const +{ + return parsed_cert->issuer; +} + +bool +Certificate::is_ca() const +{ + return parsed_cert->is_ca; +} + +Certificate::ExpirationStatus +Certificate::expiration_status() const +{ + return parsed_cert->expiration_status(); +} + +std::optional +Certificate::subject_key_id() const +{ + return parsed_cert->subject_key_id; +} + +std::optional +Certificate::authority_key_id() const +{ + return parsed_cert->authority_key_id; +} + +std::vector +Certificate::email_addresses() const +{ + std::vector emails; + for (const auto& name : parsed_cert->sub_alt_names) { + if (tls::var::holds_alternative(name)) { + emails.emplace_back(tls::var::get(name).value); + } + } + return emails; +} + +std::vector +Certificate::dns_names() const +{ + std::vector domains; + for (const auto& name : parsed_cert->sub_alt_names) { + if (tls::var::holds_alternative(name)) { + domains.emplace_back(tls::var::get(name).value); + } + } + + return domains; +} + +bytes +Certificate::hash() const +{ + return parsed_cert->hash; +} + +std::chrono::system_clock::time_point +Certificate::not_before() const +{ + return parsed_cert->not_before; +} + +std::chrono::system_clock::time_point +Certificate::not_after() const +{ + return parsed_cert->not_after; +} + +Signature::ID +Certificate::public_key_algorithm() const +{ + return parsed_cert->pub_key_id; +} + +Signature::ID +Certificate::signature_algorithm() const +{ + return parsed_cert->sig_algo; +} + +bool +operator==(const Certificate& lhs, const Certificate& rhs) +{ + return lhs.raw == rhs.raw; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/common.cpp b/mlspp/lib/hpke/src/common.cpp new file mode 100755 index 0000000000..dabbfd6286 --- /dev/null +++ b/mlspp/lib/hpke/src/common.cpp @@ -0,0 +1,20 @@ +#include "common.h" + +namespace mlspp::hpke { + +bytes +i2osp(uint64_t val, size_t size) +{ + auto out = bytes(size, 0); + auto max = size; + if (size > 8) { + max = 8; + } + + for (size_t i = 0; i < max; i++) { + out.at(size - i - 1) = static_cast(val >> (8 * i)); + } + return out; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/common.h b/mlspp/lib/hpke/src/common.h new file mode 100755 index 0000000000..d6938f6a1f --- /dev/null +++ b/mlspp/lib/hpke/src/common.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace mlspp::hpke { + +bytes +i2osp(uint64_t val, size_t size); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/dhkem.cpp b/mlspp/lib/hpke/src/dhkem.cpp new file mode 100755 index 0000000000..fb23c568cc --- /dev/null +++ b/mlspp/lib/hpke/src/dhkem.cpp @@ -0,0 +1,216 @@ +#include "dhkem.h" + +#include "common.h" + +namespace mlspp::hpke { + +DHKEM::PrivateKey::PrivateKey(Group::PrivateKey* group_priv_in) + : group_priv(group_priv_in) +{ +} + +std::unique_ptr +DHKEM::PrivateKey::public_key() const +{ + return group_priv->public_key(); +} + +DHKEM +make_dhkem(KEM::ID kem_id_in, const Group& group_in, const KDF& kdf_in) +{ + return { kem_id_in, group_in, kdf_in }; +} + +template<> +const DHKEM& +DHKEM::get() +{ + static const auto instance = make_dhkem(KEM::ID::DHKEM_P256_SHA256, + Group::get(), + KDF::get()); + return instance; +} + +template<> +const DHKEM& +DHKEM::get() +{ + static const auto instance = make_dhkem(KEM::ID::DHKEM_P384_SHA384, + Group::get(), + KDF::get()); + return instance; +} + +template<> +const DHKEM& +DHKEM::get() +{ + static const auto instance = make_dhkem(KEM::ID::DHKEM_P521_SHA512, + Group::get(), + KDF::get()); + return instance; +} + +template<> +const DHKEM& +DHKEM::get() +{ + static const auto instance = make_dhkem(KEM::ID::DHKEM_X25519_SHA256, + Group::get(), + KDF::get()); + return instance; +} + +#if !defined(WITH_BORINGSSL) +template<> +const DHKEM& +DHKEM::get() +{ + static const auto instance = make_dhkem(KEM::ID::DHKEM_X448_SHA512, + Group::get(), + KDF::get()); + return instance; +} +#endif + +DHKEM::DHKEM(KEM::ID kem_id_in, const Group& group_in, const KDF& kdf_in) + : KEM(kem_id_in, + kdf_in.hash_size, + group_in.pk_size, + group_in.pk_size, + group_in.sk_size) + , group(group_in) + , kdf(kdf_in) +{ + static const auto label_kem = from_ascii("KEM"); + suite_id = label_kem + i2osp(uint16_t(kem_id_in), 2); +} + +std::unique_ptr +DHKEM::generate_key_pair() const +{ + return std::make_unique( + group.generate_key_pair().release()); +} + +std::unique_ptr +DHKEM::derive_key_pair(const bytes& ikm) const +{ + return std::make_unique( + group.derive_key_pair(suite_id, ikm).release()); +} + +bytes +DHKEM::serialize(const KEM::PublicKey& pk) const +{ + const auto& gpk = dynamic_cast(pk); + return group.serialize(gpk); +} + +std::unique_ptr +DHKEM::deserialize(const bytes& enc) const +{ + return group.deserialize(enc); +} + +bytes +DHKEM::serialize_private(const KEM::PrivateKey& sk) const +{ + const auto& gsk = dynamic_cast(sk); + return group.serialize_private(*gsk.group_priv); +} + +std::unique_ptr +DHKEM::deserialize_private(const bytes& skm) const +{ + return std::make_unique(group.deserialize_private(skm).release()); +} + +std::pair +DHKEM::encap(const KEM::PublicKey& pkR) const +{ + const auto& gpkR = dynamic_cast(pkR); + + auto skE = group.generate_key_pair(); + auto pkE = skE->public_key(); + + auto zz = group.dh(*skE, gpkR); + auto enc = group.serialize(*pkE); + + auto pkRm = group.serialize(gpkR); + auto kem_context = enc + pkRm; + + auto shared_secret = extract_and_expand(zz, kem_context); + return std::make_pair(shared_secret, enc); +} + +bytes +DHKEM::decap(const bytes& enc, const KEM::PrivateKey& skR) const +{ + const auto& gskR = dynamic_cast(skR); + auto pkR = gskR.group_priv->public_key(); + auto pkE = group.deserialize(enc); + auto zz = group.dh(*gskR.group_priv, *pkE); + + auto pkRm = group.serialize(*pkR); + auto kem_context = enc + pkRm; + return extract_and_expand(zz, kem_context); +} + +std::pair +DHKEM::auth_encap(const KEM::PublicKey& pkR, const KEM::PrivateKey& skS) const +{ + const auto& gpkR = dynamic_cast(pkR); + const auto& gskS = dynamic_cast(skS); + + auto skE = group.generate_key_pair(); + auto pkE = skE->public_key(); + auto pkS = gskS.group_priv->public_key(); + + auto zzER = group.dh(*skE, gpkR); + auto zzSR = group.dh(*gskS.group_priv, gpkR); + auto zz = zzER + zzSR; + auto enc = group.serialize(*pkE); + + auto pkRm = group.serialize(gpkR); + auto pkSm = group.serialize(*pkS); + auto kem_context = enc + pkRm + pkSm; + + auto shared_secret = extract_and_expand(zz, kem_context); + return std::make_pair(shared_secret, enc); +} + +bytes +DHKEM::auth_decap(const bytes& enc, + const KEM::PublicKey& pkS, + const KEM::PrivateKey& skR) const +{ + const auto& gpkS = dynamic_cast(pkS); + const auto& gskR = dynamic_cast(skR); + + auto pkE = group.deserialize(enc); + auto pkR = gskR.group_priv->public_key(); + + auto zzER = group.dh(*gskR.group_priv, *pkE); + auto zzSR = group.dh(*gskR.group_priv, gpkS); + auto zz = zzER + zzSR; + + auto pkRm = group.serialize(*pkR); + auto pkSm = group.serialize(gpkS); + auto kem_context = enc + pkRm + pkSm; + + return extract_and_expand(zz, kem_context); +} + +bytes +DHKEM::extract_and_expand(const bytes& dh, const bytes& kem_context) const +{ + static const auto label_eae_prk = from_ascii("eae_prk"); + static const auto label_shared_secret = from_ascii("shared_secret"); + + auto eae_prk = kdf.labeled_extract(suite_id, {}, label_eae_prk, dh); + return kdf.labeled_expand( + suite_id, eae_prk, label_shared_secret, kem_context, secret_size); +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/dhkem.h b/mlspp/lib/hpke/src/dhkem.h new file mode 100755 index 0000000000..5a0feb9fca --- /dev/null +++ b/mlspp/lib/hpke/src/dhkem.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "group.h" + +namespace mlspp::hpke { + +struct DHKEM : public KEM +{ + struct PrivateKey : public KEM::PrivateKey + { + PrivateKey(Group::PrivateKey* group_priv_in); + std::unique_ptr public_key() const override; + + std::unique_ptr group_priv; + }; + + template + static const DHKEM& get(); + + ~DHKEM() override = default; + + std::unique_ptr generate_key_pair() const override; + std::unique_ptr derive_key_pair( + const bytes& ikm) const override; + + bytes serialize(const KEM::PublicKey& pk) const override; + std::unique_ptr deserialize(const bytes& enc) const override; + + bytes serialize_private(const KEM::PrivateKey& sk) const override; + std::unique_ptr deserialize_private( + const bytes& skm) const override; + + std::pair encap(const KEM::PublicKey& pk) const override; + bytes decap(const bytes& enc, const KEM::PrivateKey& sk) const override; + + std::pair auth_encap(const KEM::PublicKey& pkR, + const KEM::PrivateKey& skS) const override; + bytes auth_decap(const bytes& enc, + const KEM::PublicKey& pkS, + const KEM::PrivateKey& skR) const override; + +private: + const Group& group; + const KDF& kdf; + bytes suite_id; + + bytes extract_and_expand(const bytes& dh, const bytes& kem_context) const; + + DHKEM(KEM::ID kem_id_in, const Group& group_in, const KDF& kdf_in); + friend DHKEM make_dhkem(KEM::ID kem_id_in, + const Group& group_in, + const KDF& kdf_in); +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/digest.cpp b/mlspp/lib/hpke/src/digest.cpp new file mode 100755 index 0000000000..28b301bc1d --- /dev/null +++ b/mlspp/lib/hpke/src/digest.cpp @@ -0,0 +1,187 @@ +#include + +#include +#include +#if defined(WITH_OPENSSL3) +#include +#endif + +#include "openssl_common.h" + +namespace mlspp::hpke { + +static const EVP_MD* +openssl_digest_type(Digest::ID digest) +{ + switch (digest) { + case Digest::ID::SHA256: + return EVP_sha256(); + + case Digest::ID::SHA384: + return EVP_sha384(); + + case Digest::ID::SHA512: + return EVP_sha512(); + + default: + throw std::runtime_error("Unsupported ciphersuite"); + } +} + +#if defined(WITH_OPENSSL3) +static std::string +openssl_digest_name(Digest::ID digest) +{ + switch (digest) { + case Digest::ID::SHA256: + return OSSL_DIGEST_NAME_SHA2_256; + + case Digest::ID::SHA384: + return OSSL_DIGEST_NAME_SHA2_384; + + case Digest::ID::SHA512: + return OSSL_DIGEST_NAME_SHA2_512; + + default: + throw std::runtime_error("Unsupported digest algorithm"); + } +} +#endif + +template<> +const Digest& +Digest::get() +{ + static const Digest instance(Digest::ID::SHA256); + return instance; +} + +template<> +const Digest& +Digest::get() +{ + static const Digest instance(Digest::ID::SHA384); + return instance; +} + +template<> +const Digest& +Digest::get() +{ + static const Digest instance(Digest::ID::SHA512); + return instance; +} + +Digest::Digest(Digest::ID id_in) + : id(id_in) + , hash_size(EVP_MD_size(openssl_digest_type(id_in))) +{ +} + +bytes +Digest::hash(const bytes& data) const +{ + auto md = bytes(hash_size); + unsigned int size = 0; + const auto* type = openssl_digest_type(id); + if (1 != + EVP_Digest(data.data(), data.size(), md.data(), &size, type, nullptr)) { + throw openssl_error(); + } + + return md; +} + +bytes +Digest::hmac(const bytes& key, const bytes& data) const +{ + auto md = bytes(hash_size); + unsigned int size = 0; + const auto* type = openssl_digest_type(id); + if (nullptr == HMAC(type, + key.data(), + static_cast(key.size()), + data.data(), + static_cast(data.size()), + md.data(), + &size)) { + throw openssl_error(); + } + + return md; +} + +bytes +Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const +{ +#if defined(WITH_OPENSSL3) + auto digest_name = openssl_digest_name(id); + std::array params = { + OSSL_PARAM_construct_utf8_string( + OSSL_ALG_PARAM_DIGEST, digest_name.data(), 0), + OSSL_PARAM_construct_end() + }; + const auto mac = + make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); + const auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); +#else + const auto* type = openssl_digest_type(id); + auto ctx = make_typed_unique(HMAC_CTX_new()); +#endif + if (ctx == nullptr) { + throw openssl_error(); + } + + // Some FIPS-enabled libraries are overly conservative in their interpretation + // of NIST SP 800-131A, which requires HMAC keys to be at least 112 bits long. + // That document does not impose that requirement on HKDF, so we disable FIPS + // enforcement for purposes of HKDF. + // + // https://doi.org/10.6028/NIST.SP.800-131Ar2 + auto key_size = static_cast(key.size()); + // OpenSSL 3 does not support the flag EVP_MD_CTX_FLAG_NON_FIPS_ALLOW anymore. + // However, OpenSSL 3 in FIPS mode doesn't seem to check the HMAC key size + // constraint. +#if !defined(WITH_OPENSSL3) && !defined(WITH_BORINGSSL) + static const auto fips_min_hmac_key_len = 14; + if (FIPS_mode() != 0 && key_size < fips_min_hmac_key_len) { + HMAC_CTX_set_flags(ctx.get(), EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + } +#endif + + // Guard against sending nullptr to HMAC_Init_ex + const auto* key_data = key.data(); + const auto non_null_zero_length_key = uint8_t(0); + if (key_data == nullptr) { + key_data = &non_null_zero_length_key; + } + + auto md = bytes(hash_size); +#if defined(WITH_OPENSSL3) + if (1 != EVP_MAC_init(ctx.get(), key_data, key_size, params.data())) { + throw openssl_error(); + } + if (1 != EVP_MAC_update(ctx.get(), data.data(), data.size())) { + throw openssl_error(); + } + size_t size = 0; + if (1 != EVP_MAC_final(ctx.get(), md.data(), &size, hash_size)) { + throw openssl_error(); + } +#else + if (1 != HMAC_Init_ex(ctx.get(), key_data, key_size, type, nullptr)) { + throw openssl_error(); + } + if (1 != HMAC_Update(ctx.get(), data.data(), data.size())) { + throw openssl_error(); + } + unsigned int size = 0; + if (1 != HMAC_Final(ctx.get(), md.data(), &size)) { + throw openssl_error(); + } +#endif + + return md; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/group.cpp b/mlspp/lib/hpke/src/group.cpp new file mode 100755 index 0000000000..f9f9d7744c --- /dev/null +++ b/mlspp/lib/hpke/src/group.cpp @@ -0,0 +1,1077 @@ +#include "group.h" + +#include + +#include "common.h" +#include "openssl_common.h" + +#include "openssl/bn.h" +#include "openssl/ec.h" +#include "openssl/evp.h" +#include "openssl/obj_mac.h" +#if defined(WITH_OPENSSL3) +#include "openssl/core_names.h" +#include "openssl/param_build.h" +#endif + +namespace mlspp::hpke { + +static inline size_t +group_dh_size(Group::ID group_id); + +static inline const EVP_MD* +group_sig_digest(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + return EVP_sha256(); + case Group::ID::P384: + return EVP_sha384(); + case Group::ID::P521: + return EVP_sha512(); + + // EdDSA does its own hashing internally + case Group::ID::Ed25519: + case Group::ID::Ed448: + return nullptr; + + // Groups not used for signature + case Group::ID::X25519: + case Group::ID::X448: + throw std::runtime_error("Signature not supported for group"); + + default: + throw std::runtime_error("Unknown group"); + } +} + +/// +/// General implementation with OpenSSL EVP_PKEY +/// + +EVPGroup::EVPGroup(Group::ID group_id, const KDF& kdf) + : Group(group_id, kdf) +{ +} + +EVPGroup::PublicKey::PublicKey(EVP_PKEY* pkey_in) + : pkey(pkey_in, typed_delete) +{ +} + +EVPGroup::PrivateKey::PrivateKey(EVP_PKEY* pkey_in) + : pkey(pkey_in, typed_delete) +{ +} + +std::unique_ptr +EVPGroup::PrivateKey::public_key() const +{ + if (1 != EVP_PKEY_up_ref(pkey.get())) { + throw openssl_error(); + } + return std::make_unique(pkey.get()); +} + +std::unique_ptr +EVPGroup::generate_key_pair() const +{ + return derive_key_pair({}, random_bytes(sk_size)); +} + +bytes +EVPGroup::dh(const Group::PrivateKey& sk, const Group::PublicKey& pk) const +{ + const auto& rsk = dynamic_cast(sk); + const auto& rpk = dynamic_cast(pk); + + // This and the next line are acceptable because the OpenSSL + // functions fail to mark the required EVP_PKEYs as const, even + // though they are not modified. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + auto* priv_pkey = const_cast(rsk.pkey.get()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + auto* pub_pkey = const_cast(rpk.pkey.get()); + + auto ctx = make_typed_unique(EVP_PKEY_CTX_new(priv_pkey, nullptr)); + if (ctx == nullptr) { + throw openssl_error(); + } + + if (1 != EVP_PKEY_derive_init(ctx.get())) { + throw openssl_error(); + } + + if (1 != EVP_PKEY_derive_set_peer(ctx.get(), pub_pkey)) { + throw openssl_error(); + } + + size_t out_len = 0; + if (1 != EVP_PKEY_derive(ctx.get(), nullptr, &out_len)) { + throw openssl_error(); + } + + bytes out(out_len); + uint8_t* ptr = out.data(); + if (1 != (EVP_PKEY_derive(ctx.get(), ptr, &out_len))) { + throw openssl_error(); + } + + return out; +} + +bytes +EVPGroup::sign(const bytes& data, const Group::PrivateKey& sk) const +{ + const auto& rsk = dynamic_cast(sk); + + auto ctx = make_typed_unique(EVP_MD_CTX_create()); + if (ctx == nullptr) { + throw openssl_error(); + } + + const auto* digest = group_sig_digest(id); + if (1 != + EVP_DigestSignInit(ctx.get(), nullptr, digest, nullptr, rsk.pkey.get())) { + throw openssl_error(); + } + + size_t siglen = EVP_PKEY_size(rsk.pkey.get()); + bytes sig(siglen); + if (1 != EVP_DigestSign( + ctx.get(), sig.data(), &siglen, data.data(), data.size())) { + throw openssl_error(); + } + + sig.resize(siglen); + return sig; +} + +bool +EVPGroup::verify(const bytes& data, + const bytes& sig, + const Group::PublicKey& pk) const +{ + const auto& rpk = dynamic_cast(pk); + + auto ctx = make_typed_unique(EVP_MD_CTX_create()); + if (ctx == nullptr) { + throw openssl_error(); + } + + const auto* digest = group_sig_digest(id); + if (1 != EVP_DigestVerifyInit( + ctx.get(), nullptr, digest, nullptr, rpk.pkey.get())) { + throw openssl_error(); + } + + auto rv = EVP_DigestVerify( + ctx.get(), sig.data(), sig.size(), data.data(), data.size()); + + return rv == 1; +} + +/// +/// DH over "normal" curves +/// + +struct ECKeyGroup : public EVPGroup +{ + ECKeyGroup(Group::ID group_id, const KDF& kdf) + : EVPGroup(group_id, kdf) + , curve_nid(group_to_nid(group_id)) + { + } + +#if defined(WITH_OPENSSL3) + typed_unique_ptr keypair_evp_key( + const typed_unique_ptr& priv) const + { + const auto* name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); + } + + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + auto pt = make_typed_unique(EC_POINT_new(group.get())); + if (pt == nullptr) { + throw openssl_error(); + } + + if (1 != EC_POINT_mul( + group.get(), pt.get(), priv.get(), nullptr, nullptr, nullptr)) { + throw openssl_error(); + } + + const auto pt_size = EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (0 == pt_size) { + throw openssl_error(); + } + + bytes pub(pt_size); + if (EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + pub.data(), + pt_size, + nullptr) != pt_size) { + throw openssl_error(); + } + + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || + 1 != OSSL_PARAM_BLD_push_utf8_string( + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + 1 != OSSL_PARAM_BLD_push_BN( + builder.get(), OSSL_PKEY_PARAM_PRIV_KEY, priv.get()) || + 1 != + OSSL_PARAM_BLD_push_octet_string( + builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + throw openssl_error(); + } + + auto params = make_typed_unique(OSSL_PARAM_BLD_to_param(builder.get())); + auto ctx = + make_typed_unique(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)); + auto key = make_typed_unique(EVP_PKEY_new()); + auto* key_ptr = key.get(); + if (params == nullptr || ctx == nullptr || key == nullptr || + EVP_PKEY_fromdata_init(ctx.get()) <= 0 || + EVP_PKEY_fromdata( + ctx.get(), &key_ptr, EVP_PKEY_KEYPAIR, params.get()) <= 0) { + throw openssl_error(); + } + ctx.reset(); + + ctx = make_typed_unique( + EVP_PKEY_CTX_new_from_pkey(nullptr, key.get(), nullptr)); + if (EVP_PKEY_check(ctx.get()) <= 0) { + throw openssl_error(); + } + + return key; + } + + typed_unique_ptr public_evp_key(const bytes& pub) const + { + const auto* name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); + } + + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || + 1 != OSSL_PARAM_BLD_push_utf8_string( + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + 1 != + OSSL_PARAM_BLD_push_octet_string( + builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + throw openssl_error(); + } + + auto params = make_typed_unique(OSSL_PARAM_BLD_to_param(builder.get())); + auto ctx = + make_typed_unique(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)); + auto key = make_typed_unique(EVP_PKEY_new()); + auto* key_ptr = key.get(); + if (params == nullptr || ctx == nullptr || key == nullptr || + EVP_PKEY_fromdata_init(ctx.get()) <= 0 || + EVP_PKEY_fromdata( + ctx.get(), &key_ptr, EVP_PKEY_KEYPAIR, params.get()) <= 0) { + throw openssl_error(); + } + ctx.reset(); + + ctx = make_typed_unique( + EVP_PKEY_CTX_new_from_pkey(nullptr, key.get(), nullptr)); + if (EVP_PKEY_public_check(ctx.get()) <= 0) { + throw openssl_error(); + } + + return key; + } +#endif + + std::unique_ptr derive_key_pair( + const bytes& suite_id, + const bytes& ikm) const override + { + static const int retry_limit = 255; + static const auto label_dkp_prk = from_ascii("dkp_prk"); + static const auto label_candidate = from_ascii("candidate"); + + auto dkp_prk = kdf.labeled_extract(suite_id, {}, label_dkp_prk, ikm); + +#if defined(WITH_OPENSSL3) + auto* group = EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid); + auto group_ptr = make_typed_unique(group); +#else + auto eckey = new_ec_key(); + const auto* group = EC_KEY_get0_group(eckey.get()); +#endif + + auto order = make_typed_unique(BN_new()); + if (1 != EC_GROUP_get_order(group, order.get(), nullptr)) { + throw openssl_error(); + } + + auto sk = make_typed_unique(BN_new()); + BN_zero(sk.get()); + + auto counter = int(0); + while (BN_is_zero(sk.get()) != 0 || BN_cmp(sk.get(), order.get()) != -1) { + auto ctr = i2osp(counter, 1); + auto candidate = + kdf.labeled_expand(suite_id, dkp_prk, label_candidate, ctr, sk_size); + candidate.at(0) &= bitmask(); + sk.reset(BN_bin2bn( + candidate.data(), static_cast(candidate.size()), nullptr)); + + counter += 1; + if (counter > retry_limit) { + throw std::runtime_error("DeriveKeyPair iteration limit exceeded"); + } + } + +#if defined(WITH_OPENSSL3) + auto key = keypair_evp_key(sk); + return std::make_unique(key.release()); +#else + auto pt = make_typed_unique(EC_POINT_new(group)); + EC_POINT_mul(group, pt.get(), sk.get(), nullptr, nullptr, nullptr); + + EC_KEY_set_private_key(eckey.get(), sk.get()); + EC_KEY_set_public_key(eckey.get(), pt.get()); + + auto pkey = to_pkey(eckey.release()); + return std::make_unique(pkey.release()); +#endif + } + + bytes serialize(const Group::PublicKey& pk) const override + { + const auto& rpk = dynamic_cast(pk); +#if defined(WITH_OPENSSL3) + OSSL_PARAM* param = nullptr; + if (1 != EVP_PKEY_todata(rpk.pkey.get(), EVP_PKEY_PUBLIC_KEY, ¶m)) { + throw openssl_error(); + } + auto param_ptr = make_typed_unique(param); + + const OSSL_PARAM* pk_param = + OSSL_PARAM_locate_const(param_ptr.get(), OSSL_PKEY_PARAM_PUB_KEY); + if (pk_param == nullptr) { + return bytes({}, 0); + } + + size_t len = 0; + if (1 != OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { + return bytes({}, 0); + } + + bytes buf(len); + void* data_ptr = buf.data(); + if (1 != OSSL_PARAM_get_octet_string(pk_param, &data_ptr, len, nullptr)) { + return bytes({}, 0); + } + + // Prior to OpenSSL 3.0.8, we will always get compressed point from + // OSSL_PKEY_PARAM_PUB_KEY, so we will have to do the following conversion. + // From OpenSSL 3.0.8, we can obtain the uncompressed point value by setting + // OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT appropriately. + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + return bytes({}, 0); + } + auto point = make_typed_unique(EC_POINT_new(group.get())); + const auto* oct_ptr = static_cast(data_ptr); + if (1 != + EC_POINT_oct2point(group.get(), point.get(), oct_ptr, len, nullptr)) { + return bytes({}, 0); + } + len = EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (0 == len) { + return bytes({}, 0); + } + bytes out(len); + auto* data = out.data(); + if (EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + data, + len, + nullptr) != len) { + return bytes({}, 0); + } +#else + auto* pub = EVP_PKEY_get0_EC_KEY(rpk.pkey.get()); + + auto len = i2o_ECPublicKey(pub, nullptr); + if (len != static_cast(pk_size)) { + throw openssl_error(); + } + + bytes out(len); + auto* data = out.data(); + if (i2o_ECPublicKey(pub, &data) == 0) { + throw openssl_error(); + } +#endif + return out; + } + + std::unique_ptr deserialize(const bytes& enc) const override + { +#if defined(WITH_OPENSSL3) + auto key = public_evp_key(enc); + if (key == nullptr) { + throw std::runtime_error("Unable to deserialize the public key"); + } + return std::make_unique(key.release()); +#else + auto eckey = new_ec_key(); + auto* eckey_ptr = eckey.get(); + const auto* data_ptr = enc.data(); + if (nullptr == + o2i_ECPublicKey(&eckey_ptr, + &data_ptr, + static_cast( // NOLINT(google-runtime-int) + enc.size()))) { + throw openssl_error(); + } + + auto pkey = to_pkey(eckey.release()); + return std::make_unique(pkey.release()); +#endif + } + + bytes serialize_private(const Group::PrivateKey& sk) const override + { + const auto& rsk = dynamic_cast(sk); +#if defined(WITH_OPENSSL3) + OSSL_PARAM* param = nullptr; + if (1 != EVP_PKEY_todata(rsk.pkey.get(), EVP_PKEY_KEYPAIR, ¶m)) { + throw openssl_error(); + } + auto param_ptr = make_typed_unique(param); + + const OSSL_PARAM* sk_param = + OSSL_PARAM_locate_const(param_ptr.get(), OSSL_PKEY_PARAM_PRIV_KEY); + if (sk_param == nullptr) { + return bytes({}, 0); + } + + BIGNUM* d = nullptr; + if (1 != OSSL_PARAM_get_BN(sk_param, &d)) { + return bytes({}, 0); + } + auto d_ptr = make_typed_unique(d); +#else + auto* eckey = EVP_PKEY_get0_EC_KEY(rsk.pkey.get()); + const auto* d = EC_KEY_get0_private_key(eckey); +#endif + + auto out = bytes(BN_num_bytes(d)); +#if WITH_BORINGSSL + // In BoringSSL, BN_bn2bin returns size_t + const auto out_size = out.size(); +#else + // In OpenSSL, BN_bn2bin returns int + const auto out_size = static_cast(out.size()); +#endif + if (BN_bn2bin(d, out.data()) != out_size) { + throw openssl_error(); + } + + const auto zeros_needed = group_dh_size(id) - out.size(); + auto leading_zeros = bytes(zeros_needed, 0); + return leading_zeros + out; + } + + std::unique_ptr deserialize_private( + const bytes& skm) const override + { +#if defined(WITH_OPENSSL3) + auto priv = make_typed_unique( + BN_bin2bn(skm.data(), static_cast(skm.size()), nullptr)); + if (priv == nullptr) { + throw std::runtime_error("Unable to deserialize the private key"); + } + auto key = keypair_evp_key(priv); + return std::make_unique(key.release()); +#else + auto eckey = new_ec_key(); + const auto* group = EC_KEY_get0_group(eckey.get()); + const auto d = make_typed_unique( + BN_bin2bn(skm.data(), static_cast(skm.size()), nullptr)); + auto pt = make_typed_unique(EC_POINT_new(group)); + + EC_POINT_mul(group, pt.get(), d.get(), nullptr, nullptr, nullptr); + EC_KEY_set_private_key(eckey.get(), d.get()); + EC_KEY_set_public_key(eckey.get(), pt.get()); + + auto pkey = to_pkey(eckey.release()); + return std::make_unique(pkey.release()); +#endif + } + + // EC Key + std::tuple coordinates( + const Group::PublicKey& pk) const override + { + auto bn_x = make_typed_unique(BN_new()); + auto bn_y = make_typed_unique(BN_new()); + const auto& rpk = dynamic_cast(pk); + +#if defined(WITH_OPENSSL3) + // Raw pointer OK here because it becomes managed as soon as possible + OSSL_PARAM* param_ptr = nullptr; + if (1 != EVP_PKEY_todata(rpk.pkey.get(), EVP_PKEY_PUBLIC_KEY, ¶m_ptr)) { + throw openssl_error(); + } + + auto param = make_typed_unique(param_ptr); + + // Raw pointer OK here because it is non-owning + const auto* pk_param = + OSSL_PARAM_locate_const(param.get(), OSSL_PKEY_PARAM_PUB_KEY); + if (pk_param == nullptr) { + throw std::runtime_error("Failed to locate OSSL_PKEY_PARAM_PUB_KEY"); + } + + // Copy the octet string representation of the key into a buffer + auto len = size_t(0); + if (1 != OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { + throw std::runtime_error("Failed to get OSSL_PKEY_PARAM_PUB_KEY len"); + } + + auto buf = bytes(len); + auto* buf_ptr = buf.data(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + auto* buf_ptr_void = reinterpret_cast(buf_ptr); + if (1 != + OSSL_PARAM_get_octet_string(pk_param, &buf_ptr_void, len, nullptr)) { + throw std::runtime_error("Failed to get OSSL_PKEY_PARAM_PUB_KEY data"); + } + + // Parse the octet string representation into an EC_POINT + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + auto point = make_typed_unique(EC_POINT_new(group.get())); + if (point == nullptr) { + throw openssl_error(); + } + + if (1 != + EC_POINT_oct2point(group.get(), point.get(), buf_ptr, len, nullptr)) { + throw openssl_error(); + } + + // Retrieve the affine coordinates of the point + if (1 != EC_POINT_get_affine_coordinates( + group.get(), point.get(), bn_x.get(), bn_y.get(), nullptr)) { + throw openssl_error(); + } +#else + // Raw pointers are non-owning + auto* pub = EVP_PKEY_get0_EC_KEY(rpk.pkey.get()); + const auto* point = EC_KEY_get0_public_key(pub); + const auto* group = EC_KEY_get0_group(pub); + + if (1 != EC_POINT_get_affine_coordinates_GFp( + group, point, bn_x.get(), bn_y.get(), nullptr)) { + throw openssl_error(); + } +#endif + const auto x_size = BN_num_bytes(bn_x.get()); + auto x = bytes(x_size); + if (BN_bn2bin(bn_x.get(), x.data()) != x_size) { + throw openssl_error(); + } + + const auto y_size = BN_num_bytes(bn_y.get()); + auto y = bytes(y_size); + if (BN_bn2bin(bn_y.get(), y.data()) != y_size) { + throw openssl_error(); + } + + const auto zeros_needed_x = dh_size - x.size(); + const auto zeros_needed_y = dh_size - y.size(); + auto leading_zeros_x = bytes(zeros_needed_x, 0); + auto leading_zeros_y = bytes(zeros_needed_y, 0); + + return { leading_zeros_x + x, leading_zeros_y + y }; + } + + // EC Key + std::unique_ptr public_key_from_coordinates( + const bytes& x, + const bytes& y) const override + { + auto bn_x = make_typed_unique( + BN_bin2bn(x.data(), static_cast(x.size()), nullptr)); + auto bn_y = make_typed_unique( + BN_bin2bn(y.data(), static_cast(y.size()), nullptr)); + + if (bn_x == nullptr || bn_y == nullptr) { + throw std::runtime_error("Failed to convert bn_x or bn_y"); + } + +#if defined(WITH_OPENSSL3) + const auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw std::runtime_error("Failed to create EC_GROUP"); + } + + // Construct a point with the given coordinates + auto point = make_typed_unique(EC_POINT_new(group.get())); + if (group == nullptr) { + throw std::runtime_error("Failed to create EC_POINT"); + } + + if (1 != EC_POINT_set_affine_coordinates( + group.get(), point.get(), bn_x.get(), bn_y.get(), nullptr)) { + throw openssl_error(); + } + + // Serialize the point + const auto point_size = EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (0 == point_size) { + throw openssl_error(); + } + + auto pub = bytes(point_size); + if (EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + pub.data(), + point_size, + nullptr) != point_size) { + throw openssl_error(); + } + + // Initialize a public key from the serialized point + auto key = public_evp_key(pub); + return std::make_unique(key.release()); +#else + auto eckey = new_ec_key(); + if (eckey == nullptr) { + throw std::runtime_error("Failed to create EC_KEY"); + } + + // Group pointer is non-owning + const auto* group = EC_KEY_get0_group(eckey.get()); + auto point = make_typed_unique(EC_POINT_new(group)); + + if (1 != EC_POINT_set_affine_coordinates_GFp( + group, point.get(), bn_x.get(), bn_y.get(), nullptr)) { + throw openssl_error(); + } + + if (1 != EC_KEY_set_public_key(eckey.get(), point.get())) { + throw openssl_error(); + } + + auto pkey = to_pkey(eckey.release()); + return std::make_unique(pkey.release()); +#endif + } + +private: + int curve_nid; + +#if !defined(WITH_OPENSSL3) + typed_unique_ptr new_ec_key() const + { + return make_typed_unique(EC_KEY_new_by_curve_name(curve_nid)); + } + + static typed_unique_ptr to_pkey(EC_KEY* eckey) + { + auto* pkey = EVP_PKEY_new(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return make_typed_unique(pkey); + } +#endif + + static inline int group_to_nid(Group::ID group_id) + { + switch (group_id) { + case Group::ID::P256: + return NID_X9_62_prime256v1; + case Group::ID::P384: + return NID_secp384r1; + case Group::ID::P521: + return NID_secp521r1; + default: + throw std::runtime_error("Unsupported algorithm"); + } + } + + uint8_t bitmask() const + { + switch (id) { + case Group::ID::P256: + case Group::ID::P384: + return 0xff; + + case Group::ID::P521: + return 0x01; + + default: + throw std::runtime_error("Unsupported algorithm"); + } + } +}; + +/// +/// DH over "raw" curves +/// + +struct RawKeyGroup : public EVPGroup +{ + RawKeyGroup(Group::ID group_id, const KDF& kdf) + : EVPGroup(group_id, kdf) + , evp_type(group_to_evp(group_id)) + { + } + + template + static const RawKeyGroup instance; + + std::unique_ptr derive_key_pair( + const bytes& suite_id, + const bytes& ikm) const override + { + static const auto label_dkp_prk = from_ascii("dkp_prk"); + static const auto label_sk = from_ascii("sk"); + + auto dkp_prk = kdf.labeled_extract(suite_id, {}, label_dkp_prk, ikm); + auto skm = kdf.labeled_expand(suite_id, dkp_prk, label_sk, {}, sk_size); + return deserialize_private(skm); + } + + bytes serialize(const Group::PublicKey& pk) const override + { + const auto& rpk = dynamic_cast(pk); + auto raw = bytes(pk_size); + auto* data_ptr = raw.data(); + auto data_len = raw.size(); + if (1 != EVP_PKEY_get_raw_public_key(rpk.pkey.get(), data_ptr, &data_len)) { + throw openssl_error(); + } + + return raw; + } + + std::unique_ptr deserialize(const bytes& enc) const override + { + auto* pkey = + EVP_PKEY_new_raw_public_key(evp_type, nullptr, enc.data(), enc.size()); + if (pkey == nullptr) { + throw openssl_error(); + } + + return std::make_unique(pkey); + } + + bytes serialize_private(const Group::PrivateKey& sk) const override + { + const auto& rsk = dynamic_cast(sk); + auto raw = bytes(sk_size); + auto* data_ptr = raw.data(); + auto data_len = raw.size(); + if (1 != + EVP_PKEY_get_raw_private_key(rsk.pkey.get(), data_ptr, &data_len)) { + throw openssl_error(); + } + + return raw; + } + + std::unique_ptr deserialize_private( + const bytes& skm) const override + { + auto* pkey = + EVP_PKEY_new_raw_private_key(evp_type, nullptr, skm.data(), skm.size()); + if (pkey == nullptr) { + throw openssl_error(); + } + + return std::make_unique(pkey); + } + + // Raw Key + std::tuple coordinates( + const Group::PublicKey& pk) const override + { + const auto& rpk = dynamic_cast(pk); + auto raw = bytes(pk_size); + auto* data_ptr = raw.data(); + auto data_len = raw.size(); + + if (1 != EVP_PKEY_get_raw_public_key(rpk.pkey.get(), data_ptr, &data_len)) { + throw openssl_error(); + } + + return { raw, {} }; + } + + // Raw Key + std::unique_ptr public_key_from_coordinates( + const bytes& x, + const bytes& /* y */) const override + { + return deserialize(x); + } + +private: + const int evp_type; + + static inline int group_to_evp(Group::ID group_id) + { + switch (group_id) { + case Group::ID::X25519: + return EVP_PKEY_X25519; + case Group::ID::X448: + return EVP_PKEY_X448; + case Group::ID::Ed25519: + return EVP_PKEY_ED25519; + case Group::ID::Ed448: + return EVP_PKEY_ED448; + default: + throw std::runtime_error("Unsupported algorithm"); + } + } +}; + +/// +/// General DH group +/// + +template<> +const Group& +Group::get() +{ + static const ECKeyGroup instance(Group::ID::P256, + KDF::get()); + + return instance; +} + +template<> +const Group& +Group::get() +{ + static const ECKeyGroup instance(Group::ID::P384, + KDF::get()); + + return instance; +} + +template<> +const Group& +Group::get() +{ + static const ECKeyGroup instance(Group::ID::P521, + KDF::get()); + + return instance; +} + +template<> +const Group& +Group::get() +{ + static const RawKeyGroup instance(Group::ID::X25519, + KDF::get()); + return instance; +} + +template<> +const Group& +Group::get() +{ + static const RawKeyGroup instance(Group::ID::Ed25519, + KDF::get()); + return instance; +} + +// BoringSSL doesn't support X448 / Ed448 +#if !defined(WITH_BORINGSSL) +template<> +const Group& +Group::get() +{ + static const RawKeyGroup instance(Group::ID::X448, + KDF::get()); + return instance; +} +#endif + +template<> +const Group& +Group::get() +{ + static const RawKeyGroup instance(Group::ID::Ed448, + KDF::get()); + return instance; +} + +static inline size_t +group_dh_size(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + return 32; + case Group::ID::P384: + return 48; + case Group::ID::P521: + return 66; + case Group::ID::X25519: + return 32; + case Group::ID::X448: + return 56; + + // Non-DH groups + case Group::ID::Ed25519: + case Group::ID::Ed448: + return 0; + + default: + throw std::runtime_error("Unknown group"); + } +} + +static inline size_t +group_pk_size(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + return 65; + case Group::ID::P384: + return 97; + case Group::ID::P521: + return 133; + case Group::ID::X25519: + case Group::ID::Ed25519: + return 32; + case Group::ID::X448: + return 56; + case Group::ID::Ed448: + return 57; + + default: + throw std::runtime_error("Unknown group"); + } +} + +static inline size_t +group_sk_size(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + return 32; + case Group::ID::P384: + return 48; + case Group::ID::P521: + return 66; + case Group::ID::X25519: + case Group::ID::Ed25519: + return 32; + case Group::ID::X448: + return 56; + case Group::ID::Ed448: + return 57; + + default: + throw std::runtime_error("Unknown group"); + } +} + +static inline std::string +group_jwk_curve_name(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + return "P-256"; + case Group::ID::P384: + return "P-384"; + case Group::ID::P521: + return "P-521"; + case Group::ID::Ed25519: + return "Ed25519"; + case Group::ID::Ed448: + return "Ed448"; + case Group::ID::X25519: + return "X25519"; + case Group::ID::X448: + return "X448"; + default: + throw std::runtime_error("Unknown group"); + } +} + +static inline std::string +group_jwk_key_type(Group::ID group_id) +{ + switch (group_id) { + case Group::ID::P256: + case Group::ID::P384: + case Group::ID::P521: + return "EC"; + case Group::ID::Ed25519: + case Group::ID::Ed448: + case Group::ID::X25519: + case Group::ID::X448: + return "OKP"; + default: + throw std::runtime_error("Unknown group"); + } +} + +Group::Group(ID group_id_in, const KDF& kdf_in) + : id(group_id_in) + , dh_size(group_dh_size(group_id_in)) + , pk_size(group_pk_size(group_id_in)) + , sk_size(group_sk_size(group_id_in)) + , jwk_key_type(group_jwk_key_type(group_id_in)) + , jwk_curve_name(group_jwk_curve_name(group_id_in)) + , kdf(kdf_in) +{ +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/group.h b/mlspp/lib/hpke/src/group.h new file mode 100755 index 0000000000..73b52c715f --- /dev/null +++ b/mlspp/lib/hpke/src/group.h @@ -0,0 +1,116 @@ +#pragma once + +#include +#include + +#include "openssl_common.h" +#include + +namespace mlspp::hpke { + +struct Group +{ + enum struct ID : uint8_t + { + P256, + P384, + P521, + X25519, + X448, + Ed25519, + Ed448, + }; + + struct PublicKey + : public KEM::PublicKey + , public Signature::PublicKey + { + virtual ~PublicKey() = default; + }; + + struct PrivateKey + { + virtual ~PrivateKey() = default; + virtual std::unique_ptr public_key() const = 0; + }; + + template + static const Group& get(); + + virtual ~Group() = default; + + const ID id; + const size_t dh_size; + const size_t pk_size; + const size_t sk_size; + const std::string jwk_key_type; + const std::string jwk_curve_name; + + virtual std::unique_ptr generate_key_pair() const = 0; + virtual std::unique_ptr derive_key_pair( + const bytes& suite_id, + const bytes& ikm) const = 0; + + virtual bytes serialize(const PublicKey& pk) const = 0; + virtual std::unique_ptr deserialize(const bytes& enc) const = 0; + + virtual bytes serialize_private(const PrivateKey& sk) const = 0; + virtual std::unique_ptr deserialize_private( + const bytes& skm) const = 0; + + virtual bytes dh(const PrivateKey& sk, const PublicKey& pk) const = 0; + + virtual bytes sign(const bytes& data, const PrivateKey& sk) const = 0; + virtual bool verify(const bytes& data, + const bytes& sig, + const PublicKey& pk) const = 0; + + virtual std::tuple coordinates(const PublicKey& pk) const = 0; + virtual std::unique_ptr public_key_from_coordinates( + const bytes& x, + const bytes& y) const = 0; + +protected: + const KDF& kdf; + + friend struct DHKEM; + + Group(ID group_id_in, const KDF& kdf_in); +}; + +struct EVPGroup : public Group +{ + EVPGroup(Group::ID group_id, const KDF& kdf); + + struct PublicKey : public Group::PublicKey + { + explicit PublicKey(EVP_PKEY* pkey_in); + ~PublicKey() override = default; + + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) + typed_unique_ptr pkey; + }; + + struct PrivateKey : public Group::PrivateKey + { + explicit PrivateKey(EVP_PKEY* pkey_in); + ~PrivateKey() override = default; + + std::unique_ptr public_key() const override; + + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) + typed_unique_ptr pkey; + }; + + std::unique_ptr generate_key_pair() const override; + + bytes dh(const Group::PrivateKey& sk, + const Group::PublicKey& pk) const override; + + bytes sign(const bytes& data, const Group::PrivateKey& sk) const override; + bool verify(const bytes& data, + const bytes& sig, + const Group::PublicKey& pk) const override; +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/hkdf.cpp b/mlspp/lib/hpke/src/hkdf.cpp new file mode 100755 index 0000000000..274b4ad25a --- /dev/null +++ b/mlspp/lib/hpke/src/hkdf.cpp @@ -0,0 +1,79 @@ +#include "hkdf.h" +#include "openssl_common.h" + +#include +#include +#include + +namespace mlspp::hpke { + +template<> +const HKDF& +HKDF::get() +{ + static const HKDF instance(Digest::get()); + return instance; +} + +template<> +const HKDF& +HKDF::get() +{ + static const HKDF instance(Digest::get()); + return instance; +} + +template<> +const HKDF& +HKDF::get() +{ + static const HKDF instance(Digest::get()); + return instance; +} + +static KDF::ID +digest_to_kdf(Digest::ID digest_id) +{ + switch (digest_id) { + case Digest::ID::SHA256: + return KDF::ID::HKDF_SHA256; + case Digest::ID::SHA384: + return KDF::ID::HKDF_SHA384; + case Digest::ID::SHA512: + return KDF::ID::HKDF_SHA512; + } + + throw std::runtime_error("Unsupported algorithm"); +} + +HKDF::HKDF(const Digest& digest_in) + : KDF(digest_to_kdf(digest_in.id), digest_in.hash_size) + , digest(digest_in) +{ +} + +bytes +HKDF::extract(const bytes& salt, const bytes& ikm) const +{ + return digest.hmac_for_hkdf_extract(salt, ikm); +} + +bytes +HKDF::expand(const bytes& prk, const bytes& info, size_t size) const +{ + auto okm = bytes{}; + auto i = uint8_t(0x00); + auto Ti = bytes{}; + while (okm.size() < size) { + i += 1; + auto block = Ti + info + bytes{ i }; + + Ti = digest.hmac(prk, block); + okm += Ti; + } + + okm.resize(size); + return okm; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/hkdf.h b/mlspp/lib/hpke/src/hkdf.h new file mode 100755 index 0000000000..e6951be6b5 --- /dev/null +++ b/mlspp/lib/hpke/src/hkdf.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace mlspp::hpke { + +struct HKDF : public KDF +{ + template + static const HKDF& get(); + + ~HKDF() override = default; + + bytes extract(const bytes& salt, const bytes& ikm) const override; + bytes expand(const bytes& prk, const bytes& info, size_t size) const override; + +private: + const Digest& digest; + + explicit HKDF(const Digest& digest_in); +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/hpke.cpp b/mlspp/lib/hpke/src/hpke.cpp new file mode 100755 index 0000000000..7ee2faf670 --- /dev/null +++ b/mlspp/lib/hpke/src/hpke.cpp @@ -0,0 +1,540 @@ +#include +#include + +#include "aead_cipher.h" +#include "common.h" +#include "dhkem.h" +#include "hkdf.h" + +#include +#include +#include + +namespace mlspp::hpke { + +/// +/// Helper functions and constants +/// + +static const bytes& +label_exp() +{ + static const bytes val = from_ascii("exp"); + return val; +} + +static const bytes& +label_hpke() +{ + static const bytes val = from_ascii("HPKE"); + return val; +} + +static const bytes& +label_hpke_version() +{ + static const bytes val = from_ascii("HPKE-v1"); + return val; +} + +static const bytes& +label_info_hash() +{ + static const bytes val = from_ascii("info_hash"); + return val; +} + +static const bytes& +label_key() +{ + static const bytes val = from_ascii("key"); + return val; +} + +static const bytes& +label_base_nonce() +{ + static const bytes val = from_ascii("base_nonce"); + return val; +} + +static const bytes& +label_psk_id_hash() +{ + static const bytes val = from_ascii("psk_id_hash"); + return val; +} + +static const bytes& +label_sec() +{ + static const bytes val = from_ascii("sec"); + return val; +} + +static const bytes& +label_secret() +{ + static const bytes val = from_ascii("secret"); + return val; +} + +/// +/// Factory methods for primitives +/// + +KEM::KEM(ID id_in, + size_t secret_size_in, + size_t enc_size_in, + size_t pk_size_in, + size_t sk_size_in) + : id(id_in) + , secret_size(secret_size_in) + , enc_size(enc_size_in) + , pk_size(pk_size_in) + , sk_size(sk_size_in) +{ +} + +template<> +const KEM& +KEM::get() +{ + return DHKEM::get(); +} + +template<> +const KEM& +KEM::get() +{ + return DHKEM::get(); +} + +template<> +const KEM& +KEM::get() +{ + return DHKEM::get(); +} + +template<> +const KEM& +KEM::get() +{ + return DHKEM::get(); +} + +#if !defined(WITH_BORINGSSL) +template<> +const KEM& +KEM::get() +{ + return DHKEM::get(); +} +#endif + +bytes +KEM::serialize_private(const KEM::PrivateKey& /* unused */) const +{ + throw std::runtime_error("Not implemented"); +} + +std::unique_ptr +KEM::deserialize_private(const bytes& /* unused */) const +{ + throw std::runtime_error("Not implemented"); +} + +std::pair +KEM::auth_encap(const PublicKey& /* unused */, + const PrivateKey& /* unused */) const +{ + throw std::runtime_error("Not implemented"); +} + +bytes +KEM::auth_decap(const bytes& /* unused */, + const PublicKey& /* unused */, + const PrivateKey& /* unused */) const +{ + throw std::runtime_error("Not implemented"); +} + +template<> +const KDF& +KDF::get() +{ + return HKDF::get(); +} + +template<> +const KDF& +KDF::get() +{ + return HKDF::get(); +} + +template<> +const KDF& +KDF::get() +{ + return HKDF::get(); +} + +KDF::KDF(ID id_in, size_t hash_size_in) + : id(id_in) + , hash_size(hash_size_in) +{ +} + +bytes +KDF::labeled_extract(const bytes& suite_id, + const bytes& salt, + const bytes& label, + const bytes& ikm) const +{ + auto labeled_ikm = label_hpke_version() + suite_id + label + ikm; + return extract(salt, labeled_ikm); +} + +bytes +KDF::labeled_expand(const bytes& suite_id, + const bytes& prk, + const bytes& label, + const bytes& info, + size_t size) const +{ + auto labeled_info = + i2osp(size, 2) + label_hpke_version() + suite_id + label + info; + return expand(prk, labeled_info, size); +} + +template<> +const AEAD& +AEAD::get() +{ + return AEADCipher::get(); +} + +template<> +const AEAD& +AEAD::get() +{ + return AEADCipher::get(); +} + +template<> +const AEAD& +AEAD::get() +{ + return AEADCipher::get(); +} + +template<> +const AEAD& +AEAD::get() +{ + static const auto export_only = ExportOnlyCipher{}; + return export_only; +} + +AEAD::AEAD(ID id_in, size_t key_size_in, size_t nonce_size_in) + : id(id_in) + , key_size(key_size_in) + , nonce_size(nonce_size_in) +{ +} + +/// +/// Encryption Contexts +/// + +bytes +Context::do_export(const bytes& exporter_context, size_t size) const +{ + return kdf.labeled_expand( + suite, exporter_secret, label_sec(), exporter_context, size); +} + +bytes +Context::current_nonce() const +{ + auto curr = i2osp(seq, aead.nonce_size); + return curr ^ nonce; +} + +void +Context::increment_seq() +{ + if (seq == std::numeric_limits::max()) { + throw std::runtime_error("Sequence number overflow"); + } + + seq += 1; +} + +Context::Context(bytes suite_in, + bytes key_in, + bytes nonce_in, + bytes exporter_secret_in, + const KDF& kdf_in, + const AEAD& aead_in) + : suite(std::move(suite_in)) + , key(std::move(key_in)) + , nonce(std::move(nonce_in)) + , exporter_secret(std::move(exporter_secret_in)) + , kdf(kdf_in) + , aead(aead_in) + , seq(0) +{ +} + +bool +operator==(const Context& lhs, const Context& rhs) +{ + // TODO(RLB) Compare KDF and AEAD algorithms + auto suite = (lhs.suite == rhs.suite); + auto key = (lhs.key == rhs.key); + auto nonce = (lhs.nonce == rhs.nonce); + auto exporter_secret = (lhs.exporter_secret == rhs.exporter_secret); + auto seq = (lhs.seq == rhs.seq); + return suite && key && nonce && exporter_secret && seq; +} + +SenderContext::SenderContext(Context&& c) + : Context(std::move(c)) +{ +} + +bytes +SenderContext::seal(const bytes& aad, const bytes& pt) +{ + auto ct = aead.seal(key, current_nonce(), aad, pt); + increment_seq(); + return ct; +} + +ReceiverContext::ReceiverContext(Context&& c) + : Context(std::move(c)) +{ +} + +std::optional +ReceiverContext::open(const bytes& aad, const bytes& ct) +{ + auto maybe_pt = aead.open(key, current_nonce(), aad, ct); + increment_seq(); + return maybe_pt; +} + +/// +/// HPKE +/// + +static const bytes default_psk = {}; +static const bytes default_psk_id = {}; + +static bytes +suite_id(KEM::ID kem_id, KDF::ID kdf_id, AEAD::ID aead_id) +{ + return label_hpke() + i2osp(static_cast(kem_id), 2) + + i2osp(static_cast(kdf_id), 2) + + i2osp(static_cast(aead_id), 2); +} + +static const KEM& +select_kem(KEM::ID id) +{ + switch (id) { + case KEM::ID::DHKEM_P256_SHA256: + return KEM::get(); + case KEM::ID::DHKEM_P384_SHA384: + return KEM::get(); + case KEM::ID::DHKEM_P521_SHA512: + return KEM::get(); + case KEM::ID::DHKEM_X25519_SHA256: + return KEM::get(); +#if !defined(WITH_BORINGSSL) + case KEM::ID::DHKEM_X448_SHA512: + return KEM::get(); +#endif + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +static const KDF& +select_kdf(KDF::ID id) +{ + switch (id) { + case KDF::ID::HKDF_SHA256: + return KDF::get(); + case KDF::ID::HKDF_SHA384: + return KDF::get(); + case KDF::ID::HKDF_SHA512: + return KDF::get(); + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +static const AEAD& +select_aead(AEAD::ID id) +{ + switch (id) { + case AEAD::ID::AES_128_GCM: + return AEAD::get(); + case AEAD::ID::AES_256_GCM: + return AEAD::get(); + case AEAD::ID::CHACHA20_POLY1305: + return AEAD::get(); + case AEAD::ID::export_only: + return AEAD::get(); + default: + throw std::runtime_error("Unsupported algorithm"); + } +} + +HPKE::HPKE(KEM::ID kem_id, KDF::ID kdf_id, AEAD::ID aead_id) + : suite(suite_id(kem_id, kdf_id, aead_id)) + , kem(select_kem(kem_id)) + , kdf(select_kdf(kdf_id)) + , aead(select_aead(aead_id)) +{ +} + +HPKE::SenderInfo +HPKE::setup_base_s(const KEM::PublicKey& pkR, const bytes& info) const +{ + auto [shared_secret, enc] = kem.encap(pkR); + auto ctx = + key_schedule(Mode::base, shared_secret, info, default_psk, default_psk_id); + return std::make_pair(enc, SenderContext(std::move(ctx))); +} + +ReceiverContext +HPKE::setup_base_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info) const +{ + auto pkRm = kem.serialize(*skR.public_key()); + auto shared_secret = kem.decap(enc, skR); + auto ctx = + key_schedule(Mode::base, shared_secret, info, default_psk, default_psk_id); + return { std::move(ctx) }; +} + +HPKE::SenderInfo +HPKE::setup_psk_s(const KEM::PublicKey& pkR, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const +{ + auto [shared_secret, enc] = kem.encap(pkR); + auto ctx = key_schedule(Mode::psk, shared_secret, info, psk, psk_id); + return std::make_pair(enc, SenderContext(std::move(ctx))); +} + +ReceiverContext +HPKE::setup_psk_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const +{ + auto shared_secret = kem.decap(enc, skR); + auto ctx = key_schedule(Mode::psk, shared_secret, info, psk, psk_id); + return { std::move(ctx) }; +} + +HPKE::SenderInfo +HPKE::setup_auth_s(const KEM::PublicKey& pkR, + const bytes& info, + const KEM::PrivateKey& skS) const +{ + auto [shared_secret, enc] = kem.auth_encap(pkR, skS); + auto ctx = + key_schedule(Mode::auth, shared_secret, info, default_psk, default_psk_id); + return std::make_pair(enc, SenderContext(std::move(ctx))); +} + +ReceiverContext +HPKE::setup_auth_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const KEM::PublicKey& pkS) const +{ + auto shared_secret = kem.auth_decap(enc, pkS, skR); + auto ctx = + key_schedule(Mode::auth, shared_secret, info, default_psk, default_psk_id); + return { std::move(ctx) }; +} + +HPKE::SenderInfo +HPKE::setup_auth_psk_s(const KEM::PublicKey& pkR, + const bytes& info, + const bytes& psk, + const bytes& psk_id, + const KEM::PrivateKey& skS) const +{ + auto [shared_secret, enc] = kem.auth_encap(pkR, skS); + auto ctx = key_schedule(Mode::auth_psk, shared_secret, info, psk, psk_id); + return std::make_pair(enc, SenderContext(std::move(ctx))); +} + +ReceiverContext +HPKE::setup_auth_psk_r(const bytes& enc, + const KEM::PrivateKey& skR, + const bytes& info, + const bytes& psk, + const bytes& psk_id, + const KEM::PublicKey& pkS) const +{ + auto shared_secret = kem.auth_decap(enc, pkS, skR); + auto ctx = key_schedule(Mode::auth_psk, shared_secret, info, psk, psk_id); + return { std::move(ctx) }; +} + +bool +HPKE::verify_psk_inputs(Mode mode, const bytes& psk, const bytes& psk_id) +{ + auto got_psk = (psk != default_psk); + auto got_psk_id = (psk_id != default_psk_id); + if (got_psk != got_psk_id) { + return false; + } + + return (!got_psk && (mode == Mode::base || mode == Mode::auth)) || + (got_psk && (mode == Mode::psk || mode == Mode::auth_psk)); +} + +Context +HPKE::key_schedule(Mode mode, + const bytes& shared_secret, + const bytes& info, + const bytes& psk, + const bytes& psk_id) const +{ + if (!verify_psk_inputs(mode, psk, psk_id)) { + throw std::runtime_error("Invalid PSK inputs"); + } + + auto psk_id_hash = + kdf.labeled_extract(suite, {}, label_psk_id_hash(), psk_id); + auto info_hash = kdf.labeled_extract(suite, {}, label_info_hash(), info); + auto mode_bytes = bytes{ uint8_t(mode) }; + auto key_schedule_context = mode_bytes + psk_id_hash + info_hash; + + auto secret = kdf.labeled_extract(suite, shared_secret, label_secret(), psk); + + auto key = kdf.labeled_expand( + suite, secret, label_key(), key_schedule_context, aead.key_size); + auto nonce = kdf.labeled_expand( + suite, secret, label_base_nonce(), key_schedule_context, aead.nonce_size); + auto exporter_secret = kdf.labeled_expand( + suite, secret, label_exp(), key_schedule_context, kdf.hash_size); + + return { suite, key, nonce, exporter_secret, kdf, aead }; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/openssl_common.cpp b/mlspp/lib/hpke/src/openssl_common.cpp new file mode 100755 index 0000000000..e520059d1c --- /dev/null +++ b/mlspp/lib/hpke/src/openssl_common.cpp @@ -0,0 +1,160 @@ +#include "openssl_common.h" + +#include +#include +#include +#include +#include +#include +#if defined(WITH_OPENSSL3) +#include +#endif + +namespace mlspp::hpke { + +template<> +void +typed_delete(EVP_CIPHER_CTX* ptr) +{ + EVP_CIPHER_CTX_free(ptr); +} + +#if WITH_BORINGSSL +template<> +void +typed_delete(EVP_AEAD_CTX* ptr) +{ + EVP_AEAD_CTX_free(ptr); +} +#endif + +template<> +void +typed_delete(EVP_PKEY_CTX* ptr) +{ + EVP_PKEY_CTX_free(ptr); +} + +template<> +void +typed_delete(EVP_MD_CTX* ptr) +{ + EVP_MD_CTX_free(ptr); +} + +#if !defined(WITH_OPENSSL3) +template<> +void +typed_delete(HMAC_CTX* ptr) +{ + HMAC_CTX_free(ptr); +} +#endif + +template<> +void +typed_delete(EVP_PKEY* ptr) +{ + EVP_PKEY_free(ptr); +} + +template<> +void +typed_delete(BIGNUM* ptr) +{ + BN_free(ptr); +} + +template<> +void +typed_delete(EC_POINT* ptr) +{ + EC_POINT_free(ptr); +} + +#if !defined(WITH_OPENSSL3) +template<> +void +typed_delete(EC_KEY* ptr) +{ + EC_KEY_free(ptr); +} +#endif + +#if defined(WITH_OPENSSL3) +template<> +void +typed_delete(EVP_MAC* ptr) +{ + EVP_MAC_free(ptr); +} + +template<> +void +typed_delete(EVP_MAC_CTX* ptr) +{ + EVP_MAC_CTX_free(ptr); +} + +template<> +void +typed_delete(EC_GROUP* ptr) +{ + EC_GROUP_free(ptr); +} + +template<> +void +typed_delete(OSSL_PARAM_BLD* ptr) +{ + OSSL_PARAM_BLD_free(ptr); +} + +template<> +void +typed_delete(OSSL_PARAM* ptr) +{ + OSSL_PARAM_free(ptr); +} +#endif + +template<> +void +typed_delete(X509* ptr) +{ + X509_free(ptr); +} + +template<> +void +typed_delete(STACK_OF(GENERAL_NAME) * ptr) +{ + sk_GENERAL_NAME_pop_free(ptr, GENERAL_NAME_free); +} + +template<> +void +typed_delete(BIO* ptr) +{ + BIO_vfree(ptr); +} + +template<> +void +typed_delete(ASN1_TIME* ptr) +{ + ASN1_TIME_free(ptr); +} + +/// +/// Map OpenSSL errors to C++ exceptions +/// + +std::runtime_error +openssl_error() +{ + auto code = ERR_get_error(); + return std::runtime_error(ERR_error_string(code, nullptr)); +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/openssl_common.h b/mlspp/lib/hpke/src/openssl_common.h new file mode 100755 index 0000000000..d9282bd83b --- /dev/null +++ b/mlspp/lib/hpke/src/openssl_common.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace mlspp::hpke { + +template +void +typed_delete(T* ptr); + +template +using typed_unique_ptr = std::unique_ptr)>; + +template +typed_unique_ptr +make_typed_unique(T* ptr) +{ + return typed_unique_ptr(ptr, typed_delete); +} + +std::runtime_error +openssl_error(); + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/random.cpp b/mlspp/lib/hpke/src/random.cpp new file mode 100755 index 0000000000..6f00c6bae5 --- /dev/null +++ b/mlspp/lib/hpke/src/random.cpp @@ -0,0 +1,19 @@ +#include + +#include "openssl_common.h" + +#include + +namespace mlspp::hpke { + +bytes +random_bytes(size_t size) +{ + auto rand = bytes(size); + if (1 != RAND_bytes(rand.data(), static_cast(size))) { + throw openssl_error(); + } + return rand; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/rsa.cpp b/mlspp/lib/hpke/src/rsa.cpp new file mode 100755 index 0000000000..de6aba172f --- /dev/null +++ b/mlspp/lib/hpke/src/rsa.cpp @@ -0,0 +1,207 @@ +#include "rsa.h" + +#include "common.h" +#include "openssl/rsa.h" +#include "openssl_common.h" + +namespace mlspp::hpke { + +std::unique_ptr +RSASignature::generate_key_pair() const +{ + throw std::runtime_error("Not implemented"); +} + +std::unique_ptr +RSASignature::derive_key_pair(const bytes& /*ikm*/) const +{ + throw std::runtime_error("Not implemented"); +} + +std::unique_ptr +RSASignature::generate_key_pair(size_t bits) +{ + auto ctx = make_typed_unique(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr)); + if (ctx == nullptr) { + throw openssl_error(); + } + + if (EVP_PKEY_keygen_init(ctx.get()) <= 0) { + throw openssl_error(); + } + + // NOLINTNEXTLINE(hicpp-signed-bitwise) + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), static_cast(bits)) <= + 0) { + throw openssl_error(); + } + + auto* pkey = static_cast(nullptr); + if (EVP_PKEY_keygen(ctx.get(), &pkey) <= 0) { + throw openssl_error(); + } + + return std::make_unique(pkey); +} + +// TODO(rlb): Implement derive() with sizes + +bytes +RSASignature::serialize(const Signature::PublicKey& pk) const +{ + const auto& rpk = dynamic_cast(pk); + const int len = i2d_PublicKey(rpk.pkey.get(), nullptr); + auto raw = bytes(len); + auto* data_ptr = raw.data(); + if (len != i2d_PublicKey(rpk.pkey.get(), &data_ptr)) { + throw openssl_error(); + } + return raw; +} + +std::unique_ptr +RSASignature::deserialize(const bytes& enc) const +{ + const auto* data_ptr = enc.data(); + auto* pkey = d2i_PublicKey( + EVP_PKEY_RSA, nullptr, &data_ptr, static_cast(enc.size())); + if (pkey == nullptr) { + throw openssl_error(); + } + return std::make_unique(pkey); +} + +bytes +RSASignature::serialize_private(const Signature::PrivateKey& sk) const +{ + const auto& rsk = dynamic_cast(sk); + const int len = i2d_PrivateKey(rsk.pkey.get(), nullptr); + auto raw = bytes(len); + auto* data_ptr = raw.data(); + if (len != i2d_PrivateKey(rsk.pkey.get(), &data_ptr)) { + throw openssl_error(); + } + + return raw; +} + +std::unique_ptr +RSASignature::deserialize_private(const bytes& skm) const +{ + const auto* data_ptr = skm.data(); + auto* pkey = d2i_PrivateKey( + EVP_PKEY_RSA, nullptr, &data_ptr, static_cast(skm.size())); + if (pkey == nullptr) { + throw openssl_error(); + } + return std::make_unique(pkey); +} + +bytes +RSASignature::sign(const bytes& data, const Signature::PrivateKey& sk) const +{ + const auto& rsk = dynamic_cast(sk); + + auto ctx = make_typed_unique(EVP_MD_CTX_create()); + if (ctx == nullptr) { + throw openssl_error(); + } + + if (1 != + EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, rsk.pkey.get())) { + throw openssl_error(); + } + + size_t siglen = EVP_PKEY_size(rsk.pkey.get()); + bytes sig(siglen); + if (1 != EVP_DigestSign( + ctx.get(), sig.data(), &siglen, data.data(), data.size())) { + throw openssl_error(); + } + + sig.resize(siglen); + return sig; +} + +bool +RSASignature::verify(const bytes& data, + const bytes& sig, + const Signature::PublicKey& pk) const +{ + const auto& rpk = dynamic_cast(pk); + + auto ctx = make_typed_unique(EVP_MD_CTX_create()); + if (ctx == nullptr) { + throw openssl_error(); + } + + if (1 != + EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, rpk.pkey.get())) { + throw openssl_error(); + } + + auto rv = EVP_DigestVerify( + ctx.get(), sig.data(), sig.size(), data.data(), data.size()); + + return rv == 1; +} + +// TODO(RLB) Implement these methods. No concrete need, but might be nice for +// completeness. +std::unique_ptr +RSASignature::import_jwk_private(const std::string& /* json_str */) const +{ + throw std::runtime_error("not implemented"); +} + +std::unique_ptr +RSASignature::import_jwk(const std::string& /* json_str */) const +{ + throw std::runtime_error("not implemented"); +} + +std::string +RSASignature::export_jwk_private(const Signature::PrivateKey& /* sk */) const +{ + throw std::runtime_error("not implemented"); +} + +std::string +RSASignature::export_jwk(const Signature::PublicKey& /* pk */) const +{ + throw std::runtime_error("not implemented"); +} + +const EVP_MD* +RSASignature::digest_to_md(Digest::ID digest) +{ + // NOLINTNEXTLINE(hicpp-multiway-paths-covered) + switch (digest) { + case Digest::ID::SHA256: + return EVP_sha256(); + case Digest::ID::SHA384: + return EVP_sha384(); + case Digest::ID::SHA512: + return EVP_sha512(); + default: + throw std::runtime_error("Unsupported digest"); + } +} + +Signature::ID +RSASignature::digest_to_sig(Digest::ID digest) +{ + // NOLINTNEXTLINE(hicpp-multiway-paths-covered) + switch (digest) { + case Digest::ID::SHA256: + return Signature::ID::RSA_SHA256; + case Digest::ID::SHA384: + return Signature::ID::RSA_SHA384; + case Digest::ID::SHA512: + return Signature::ID::RSA_SHA512; + default: + throw std::runtime_error("Unsupported digest"); + } +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/rsa.h b/mlspp/lib/hpke/src/rsa.h new file mode 100755 index 0000000000..dde38bde7e --- /dev/null +++ b/mlspp/lib/hpke/src/rsa.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include + +#include "openssl_common.h" +#include +#include + +namespace mlspp::hpke { + +// XXX(RLB): There is a lot of code in RSASignature that is duplicated in +// EVPGroup. I have allowed this duplication rather than factoring it out +// because I would like to be able to cleanly remove RSA later. +struct RSASignature : public Signature +{ + struct PublicKey : public Signature::PublicKey + { + explicit PublicKey(EVP_PKEY* pkey_in) + : pkey(pkey_in, typed_delete) + { + } + + ~PublicKey() override = default; + + typed_unique_ptr pkey; + }; + + struct PrivateKey : public Signature::PrivateKey + { + explicit PrivateKey(EVP_PKEY* pkey_in) + : pkey(pkey_in, typed_delete) + { + } + + ~PrivateKey() override = default; + + std::unique_ptr public_key() const override + { + if (1 != EVP_PKEY_up_ref(pkey.get())) { + throw openssl_error(); + } + return std::make_unique(pkey.get()); + } + + typed_unique_ptr pkey; + }; + + explicit RSASignature(Digest::ID digest) + : Signature(digest_to_sig(digest)) + , md(digest_to_md(digest)) + { + } + + std::unique_ptr generate_key_pair() const override; + + std::unique_ptr derive_key_pair( + const bytes& /*ikm*/) const override; + + static std::unique_ptr generate_key_pair(size_t bits); + + // TODO(rlb): Implement derive() with sizes + + bytes serialize(const Signature::PublicKey& pk) const override; + + std::unique_ptr deserialize( + const bytes& enc) const override; + + bytes serialize_private(const Signature::PrivateKey& sk) const override; + + std::unique_ptr deserialize_private( + const bytes& skm) const override; + + bytes sign(const bytes& data, const Signature::PrivateKey& sk) const override; + + bool verify(const bytes& data, + const bytes& sig, + const Signature::PublicKey& pk) const override; + + std::unique_ptr import_jwk_private( + const std::string& json_str) const override; + std::unique_ptr import_jwk( + const std::string& json_str) const override; + std::string export_jwk_private( + const Signature::PrivateKey& sk) const override; + std::string export_jwk(const Signature::PublicKey& pk) const override; + +private: + const EVP_MD* md; + + static const EVP_MD* digest_to_md(Digest::ID digest); + + static Signature::ID digest_to_sig(Digest::ID digest); +}; + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/signature.cpp b/mlspp/lib/hpke/src/signature.cpp new file mode 100755 index 0000000000..97d7b9181c --- /dev/null +++ b/mlspp/lib/hpke/src/signature.cpp @@ -0,0 +1,344 @@ +#include +#include +#include +#include + +#include "dhkem.h" +#include "rsa.h" + +#include +#include +#include +#include +#include +#include + +using nlohmann::json; + +namespace mlspp::hpke { + +struct GroupSignature : public Signature +{ + struct PrivateKey : public Signature::PrivateKey + { + explicit PrivateKey(Group::PrivateKey* group_priv_in) + : group_priv(group_priv_in) + { + } + + std::unique_ptr public_key() const override + { + return group_priv->public_key(); + } + + std::unique_ptr group_priv; + }; + + static Signature::ID group_to_sig(Group::ID group_id) + { + switch (group_id) { + case Group::ID::P256: + return Signature::ID::P256_SHA256; + case Group::ID::P384: + return Signature::ID::P384_SHA384; + case Group::ID::P521: + return Signature::ID::P521_SHA512; + case Group::ID::Ed25519: + return Signature::ID::Ed25519; +#if !defined(WITH_BORINGSSL) + case Group::ID::Ed448: + return Signature::ID::Ed448; +#endif + default: + throw std::runtime_error("Unsupported group"); + } + } + + explicit GroupSignature(const Group& group_in) + : Signature(group_to_sig(group_in.id)) + , group(group_in) + { + } + + std::unique_ptr generate_key_pair() const override + { + return std::make_unique(group.generate_key_pair().release()); + } + + std::unique_ptr derive_key_pair( + const bytes& ikm) const override + { + return std::make_unique( + group.derive_key_pair({}, ikm).release()); + } + + bytes serialize(const Signature::PublicKey& pk) const override + { + const auto& rpk = dynamic_cast(pk); + return group.serialize(rpk); + } + + std::unique_ptr deserialize( + const bytes& enc) const override + { + return group.deserialize(enc); + } + + bytes serialize_private(const Signature::PrivateKey& sk) const override + { + const auto& rsk = dynamic_cast(sk); + return group.serialize_private(*rsk.group_priv); + } + + std::unique_ptr deserialize_private( + const bytes& skm) const override + { + return std::make_unique( + group.deserialize_private(skm).release()); + } + + bytes sign(const bytes& data, const Signature::PrivateKey& sk) const override + { + const auto& rsk = dynamic_cast(sk); + return group.sign(data, *rsk.group_priv); + } + + bool verify(const bytes& data, + const bytes& sig, + const Signature::PublicKey& pk) const override + { + const auto& rpk = dynamic_cast(pk); + return group.verify(data, sig, rpk); + } + + std::unique_ptr import_jwk_private( + const std::string& jwk_json) const override + { + const auto jwk = validate_jwk_json(jwk_json, true); + + const auto d = from_base64url(jwk.at("d")); + auto gsk = group.deserialize_private(d); + + return std::make_unique(gsk.release()); + } + + std::unique_ptr import_jwk( + const std::string& jwk_json) const override + { + const auto jwk = validate_jwk_json(jwk_json, false); + + const auto x = from_base64url(jwk.at("x")); + auto y = bytes{}; + if (jwk.contains("y")) { + y = from_base64url(jwk.at("y")); + } + + return group.public_key_from_coordinates(x, y); + } + + std::string export_jwk(const Signature::PublicKey& pk) const override + { + const auto& gpk = dynamic_cast(pk); + const auto jwk_json = export_jwk_json(gpk); + return jwk_json.dump(); + } + + std::string export_jwk_private(const Signature::PrivateKey& sk) const override + { + const auto& gssk = dynamic_cast(sk); + const auto& gsk = gssk.group_priv; + const auto gpk = gsk->public_key(); + + auto jwk_json = export_jwk_json(*gpk); + + // encode the private key + const auto enc = serialize_private(sk); + jwk_json.emplace("d", to_base64url(enc)); + + return jwk_json.dump(); + } + +private: + const Group& group; + + json validate_jwk_json(const std::string& jwk_json, bool private_key) const + { + json jwk = json::parse(jwk_json); + + if (jwk.empty() || !jwk.contains("kty") || !jwk.contains("crv") || + !jwk.contains("x") || (private_key && !jwk.contains("d"))) { + throw std::runtime_error("malformed JWK"); + } + + if (jwk.at("kty") != group.jwk_key_type) { + throw std::runtime_error("invalid JWK key type"); + } + + if (jwk.at("crv") != group.jwk_curve_name) { + throw std::runtime_error("invalid JWK curve"); + } + + return jwk; + } + + json export_jwk_json(const Group::PublicKey& pk) const + { + const auto [x, y] = group.coordinates(pk); + + json jwk = json::object({ + { "crv", group.jwk_curve_name }, + { "kty", group.jwk_key_type }, + }); + + if (group.jwk_key_type == "EC") { + jwk.emplace("x", to_base64url(x)); + jwk.emplace("y", to_base64url(y)); + } else if (group.jwk_key_type == "OKP") { + jwk.emplace("x", to_base64url(x)); + } else { + throw std::runtime_error("unknown key type"); + } + + return jwk; + } +}; + +template<> +const Signature& +Signature::get() +{ + static const auto instance = GroupSignature(Group::get()); + return instance; +} + +template<> +const Signature& +Signature::get() +{ + static const auto instance = GroupSignature(Group::get()); + return instance; +} + +template<> +const Signature& +Signature::get() +{ + static const auto instance = GroupSignature(Group::get()); + return instance; +} + +template<> +const Signature& +Signature::get() +{ + static const auto instance = GroupSignature(Group::get()); + return instance; +} + +#if !defined(WITH_BORINGSSL) +template<> +const Signature& +Signature::get() +{ + static const auto instance = GroupSignature(Group::get()); + return instance; +} +#endif + +template<> +const Signature& +Signature::get() +{ + static const auto instance = RSASignature(Digest::ID::SHA256); + return instance; +} + +template<> +const Signature& +Signature::get() +{ + static const auto instance = RSASignature(Digest::ID::SHA384); + return instance; +} + +template<> +const Signature& +Signature::get() +{ + static const auto instance = RSASignature(Digest::ID::SHA512); + return instance; +} + +Signature::Signature(Signature::ID id_in) + : id(id_in) +{ +} + +std::unique_ptr +Signature::generate_rsa(size_t bits) +{ + return RSASignature::generate_key_pair(bits); +} + +static const Signature& +sig_from_jwk(const std::string& jwk_json) +{ + using KeyTypeAndCurve = std::tuple; + static const auto alg_sig_map = std::map + { + { { "EC", "P-256" }, Signature::get() }, + { { "EC", "P-384" }, Signature::get() }, + { { "EC", "P-512" }, Signature::get() }, + { { "OKP", "Ed25519" }, Signature::get() }, +#if !defined(WITH_BORINGSSL) + { { "OKP", "Ed448" }, Signature::get() }, +#endif + // TODO(RLB): RSA + }; + + const auto jwk = json::parse(jwk_json); + const auto& kty = jwk.at("kty"); + + auto crv = std::string(""); + if (jwk.contains("crv")) { + crv = jwk.at("crv"); + } + + const auto key = KeyTypeAndCurve{ kty, crv }; + return alg_sig_map.at(key); +} + +Signature::PrivateJWK +Signature::parse_jwk_private(const std::string& jwk_json) +{ + // XXX(RLB): This JSON-parses the JWK twice. I'm assuming that this is a less + // bad cost than changing the import_jwk method signature to take `json`. + const auto& sig = sig_from_jwk(jwk_json); + const auto jwk = json::parse(jwk_json); + auto priv = sig.import_jwk_private(jwk_json); + + auto kid = std::optional{}; + if (jwk.contains("kid")) { + kid = jwk.at("kid").get(); + } + + return { sig, kid, std::move(priv) }; +} + +Signature::PublicJWK +Signature::parse_jwk(const std::string& jwk_json) +{ + // XXX(RLB): Same double-parsing comment as with `parse_jwk_private` + const auto& sig = sig_from_jwk(jwk_json); + const auto jwk = json::parse(jwk_json); + auto pub = sig.import_jwk(jwk_json); + + auto kid = std::optional{}; + if (jwk.contains("kid")) { + kid = jwk.at("kid").get(); + } + + return { sig, kid, std::move(pub) }; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/hpke/src/userinfo_vc.cpp b/mlspp/lib/hpke/src/userinfo_vc.cpp new file mode 100755 index 0000000000..fea3d8ea31 --- /dev/null +++ b/mlspp/lib/hpke/src/userinfo_vc.cpp @@ -0,0 +1,401 @@ +#include +#include +#include +#include +#include + +using nlohmann::json; + +namespace mlspp::hpke { + +static const std::string name_attr = "name"; +static const std::string sub_attr = "sub"; +static const std::string given_name_attr = "given_name"; +static const std::string family_name_attr = "family_name"; +static const std::string middle_name_attr = "middle_name"; +static const std::string nickname_attr = "nickname"; +static const std::string preferred_username_attr = "preferred_username"; +static const std::string profile_attr = "profile"; +static const std::string picture_attr = "picture"; +static const std::string website_attr = "website"; +static const std::string email_attr = "email"; +static const std::string email_verified_attr = "email_verified"; +static const std::string gender_attr = "gender"; +static const std::string birthdate_attr = "birthdate"; +static const std::string zoneinfo_attr = "zoneinfo"; +static const std::string locale_attr = "locale"; +static const std::string phone_number_attr = "phone_number"; +static const std::string phone_number_verified_attr = "phone_number_verified"; +static const std::string address_attr = "address"; +static const std::string address_formatted_attr = "formatted"; +static const std::string address_street_address_attr = "street_address"; +static const std::string address_locality_attr = "locality"; +static const std::string address_region_attr = "region"; +static const std::string address_postal_code_attr = "postal_code"; +static const std::string address_country_attr = "country"; +static const std::string updated_at_attr = "updated_at"; + +template +static std::optional +get_optional(const json& json_object, const std::string& field_name) +{ + if (!json_object.contains(field_name)) { + return std::nullopt; + } + + return { json_object.at(field_name).get() }; +} + +/// +/// ParsedCredential +/// +static const Signature& +signature_from_alg(const std::string& alg) +{ + static const auto alg_sig_map = std::map + { + { "ES256", Signature::get() }, + { "ES384", Signature::get() }, + { "ES512", Signature::get() }, + { "Ed25519", Signature::get() }, +#if !defined(WITH_BORINGSSL) + { "Ed448", Signature::get() }, +#endif + { "RS256", Signature::get() }, + { "RS384", Signature::get() }, + { "RS512", Signature::get() }, + }; + + return alg_sig_map.at(alg); +} + +static std::chrono::system_clock::time_point +epoch_time(int64_t seconds_since_epoch) +{ + const auto delta = std::chrono::seconds(seconds_since_epoch); + return std::chrono::system_clock::time_point(delta); +} + +static bool +is_ecdsa(const Signature& sig) +{ + return sig.id == Signature::ID::P256_SHA256 || + sig.id == Signature::ID::P384_SHA384 || + sig.id == Signature::ID::P521_SHA512; +} + +// OpenSSL expects ECDSA signatures to be in DER form. JWS provides the +// signature in raw R||S form. So we need to do some manual DER encoding. +static bytes +jws_to_der_sig(const bytes& jws_sig) +{ + // Inputs that are too large will result in invalid DER encodings with this + // code. At this size, the combination of the DER integer headers and the + // integer data will overflow the one-byte DER struct length. + static const auto max_sig_size = size_t(250); + if (jws_sig.size() > max_sig_size) { + throw std::runtime_error("JWS signature too large"); + } + + if (jws_sig.size() % 2 != 0) { + throw std::runtime_error("Malformed JWS signature"); + } + + const auto int_size = jws_sig.size() / 2; + const auto jws_sig_cut = + jws_sig.begin() + static_cast(int_size); + + // Compute the encoded size of R and S integer data, adding a zero byte if + // needed to clear the sign bit + const auto r_big = (jws_sig.at(0) >= 0x80); + const auto s_big = (jws_sig.at(int_size) >= 0x80); + + const auto r_size = int_size + (r_big ? 1 : 0); + const auto s_size = int_size + (s_big ? 1 : 0); + + // Compute the size of the DER-encoded signature + static const auto int_header_size = 2; + const auto r_int_size = int_header_size + r_size; + const auto s_int_size = int_header_size + s_size; + + const auto content_size = r_int_size + s_int_size; + const auto content_big = (content_size > 0x80); + + auto der_header_size = 2 + (content_big ? 1 : 0); + const auto der_size = der_header_size + content_size; + + // Allocate the DER buffer + auto der = bytes(der_size, 0); + + // Write the header + der.at(0) = 0x30; + if (content_big) { + der.at(1) = 0x81; + der.at(2) = static_cast(content_size); + } else { + der.at(1) = static_cast(content_size); + } + + // Write R, virtually padding with a zero byte if needed + const auto r_start = der_header_size; + const auto r_data_start = r_start + int_header_size + (r_big ? 1 : 0); + const auto r_data_begin = + der.begin() + static_cast(r_data_start); + + der.at(r_start) = 0x02; + der.at(r_start + 1) = static_cast(r_size); + std::copy(jws_sig.begin(), jws_sig_cut, r_data_begin); + + // Write S, virtually padding with a zero byte if needed + const auto s_start = der_header_size + r_int_size; + const auto s_data_start = s_start + int_header_size + (s_big ? 1 : 0); + const auto s_data_begin = + der.begin() + static_cast(s_data_start); + + der.at(s_start) = 0x02; + der.at(s_start + 1) = static_cast(s_size); + std::copy(jws_sig_cut, jws_sig.end(), s_data_begin); + + return der; +} + +struct UserInfoVC::ParsedCredential +{ + // Header fields + const Signature& signature_algorithm; // `alg` + std::optional key_id; // `kid` + + // Top-level Payload fields + std::string issuer; // `iss` + std::chrono::system_clock::time_point not_before; // `nbf` + std::chrono::system_clock::time_point not_after; // `exp` + + // Credential subject fields + UserInfoClaims credential_subject; + Signature::PublicJWK public_key; + + // Signature verification information + bytes to_be_signed; + bytes signature; + + ParsedCredential(const Signature& signature_algorithm_in, + std::optional key_id_in, + std::string issuer_in, + std::chrono::system_clock::time_point not_before_in, + std::chrono::system_clock::time_point not_after_in, + UserInfoClaims credential_subject_in, + Signature::PublicJWK&& public_key_in, + bytes to_be_signed_in, + bytes signature_in) + : signature_algorithm(signature_algorithm_in) + , key_id(std::move(key_id_in)) + , issuer(std::move(issuer_in)) + , not_before(not_before_in) + , not_after(not_after_in) + , credential_subject(std::move(credential_subject_in)) + , public_key(std::move(public_key_in)) + , to_be_signed(std::move(to_be_signed_in)) + , signature(std::move(signature_in)) + { + } + + static std::shared_ptr parse(const std::string& jwt) + { + // Split the JWT into its header, payload, and signature + const auto first_dot = jwt.find_first_of('.'); + const auto last_dot = jwt.find_last_of('.'); + if (first_dot == std::string::npos || last_dot == std::string::npos || + first_dot == last_dot || last_dot > jwt.length() - 2) { + throw std::runtime_error("malformed JWT; not enough '.' characters"); + } + + const auto header_b64 = jwt.substr(0, first_dot); + const auto payload_b64 = + jwt.substr(first_dot + 1, last_dot - first_dot - 1); + const auto signature_b64 = jwt.substr(last_dot + 1); + + // Parse the components + const auto header = json::parse(to_ascii(from_base64url(header_b64))); + const auto payload = json::parse(to_ascii(from_base64url(payload_b64))); + + // Prepare the validation inputs + const auto hdr = header.at("alg"); + const auto& sig = signature_from_alg(hdr); + const auto to_be_signed = from_ascii(header_b64 + "." + payload_b64); + auto signature = from_base64url(signature_b64); + if (is_ecdsa(sig)) { + signature = jws_to_der_sig(signature); + } + + auto kid = std::optional{}; + if (header.contains("kid")) { + kid = header.at("kid").get(); + } + + // Verify the VC parts + const auto& vc = payload.at("vc"); + + static const auto context = + std::vector{ { "https://www.w3.org/2018/credentials/v1" } }; + const auto vc_context = vc.at("@context").get>(); + if (vc_context != context) { + throw std::runtime_error("malformed VC: incorrect context value"); + } + + static const auto type = std::vector{ + "VerifiableCredential", + "UserInfoCredential", + }; + if (vc.at("type") != type) { + throw std::runtime_error("malformed VC: incorrect type value"); + } + + // Parse the subject public key + static const std::string did_jwk_prefix = "did:jwk:"; + const auto id = vc.at("credentialSubject").at("id").get(); + if (id.find(did_jwk_prefix) != 0) { + throw std::runtime_error("malformed UserInfo VC: ID is not did:jwk"); + } + + const auto jwk = to_ascii(from_base64url(id.substr(did_jwk_prefix.size()))); + auto public_key = Signature::parse_jwk(jwk); + + // Extract the salient parts + return std::make_shared( + sig, + kid, + + payload.at("iss"), + epoch_time(payload.at("nbf").get()), + epoch_time(payload.at("exp").get()), + + UserInfoClaims::from_json(vc.at("credentialSubject").dump()), + std::move(public_key), + + to_be_signed, + signature); + } + + bool verify(const Signature::PublicKey& issuer_key) + { + return signature_algorithm.verify(to_be_signed, signature, issuer_key); + } +}; + +/// +/// UserInfoClaims +/// +UserInfoClaims +UserInfoClaims::from_json(const std::string& cred_subject) +{ + const auto& cred_subject_json = nlohmann::json::parse(cred_subject); + + std::optional address_opt = {}; + + if (cred_subject_json.contains(address_attr)) { + auto address_json = cred_subject_json.at(address_attr); + address_opt = { + get_optional(address_json, address_formatted_attr), + get_optional(address_json, address_street_address_attr), + get_optional(address_json, address_locality_attr), + get_optional(address_json, address_region_attr), + get_optional(address_json, address_postal_code_attr), + get_optional(address_json, address_country_attr) + }; + } + + return { + get_optional(cred_subject_json, sub_attr), + get_optional(cred_subject_json, name_attr), + get_optional(cred_subject_json, given_name_attr), + get_optional(cred_subject_json, family_name_attr), + get_optional(cred_subject_json, middle_name_attr), + get_optional(cred_subject_json, nickname_attr), + get_optional(cred_subject_json, preferred_username_attr), + get_optional(cred_subject_json, profile_attr), + get_optional(cred_subject_json, picture_attr), + get_optional(cred_subject_json, website_attr), + get_optional(cred_subject_json, email_attr), + get_optional(cred_subject_json, email_verified_attr), + get_optional(cred_subject_json, gender_attr), + get_optional(cred_subject_json, birthdate_attr), + get_optional(cred_subject_json, zoneinfo_attr), + get_optional(cred_subject_json, locale_attr), + get_optional(cred_subject_json, phone_number_attr), + get_optional(cred_subject_json, phone_number_verified_attr), + address_opt, + get_optional(cred_subject_json, updated_at_attr), + }; +} + +/// +/// UserInfoVC +/// + +UserInfoVC::UserInfoVC(std::string jwt) + : parsed_cred(ParsedCredential::parse(jwt)) + , raw(std::move(jwt)) +{ +} + +const Signature& +UserInfoVC::signature_algorithm() const +{ + return parsed_cred->signature_algorithm; +} + +std::string +UserInfoVC::issuer() const +{ + return parsed_cred->issuer; +} + +std::optional +UserInfoVC::key_id() const +{ + return parsed_cred->key_id; +} + +bool +UserInfoVC::valid_from(const Signature::PublicKey& issuer_key) const +{ + return parsed_cred->verify(issuer_key); +} + +const std::string& +UserInfoVC::raw_credential() const +{ + return raw; +} + +const UserInfoClaims& +UserInfoVC::subject() const +{ + return parsed_cred->credential_subject; +} + +std::chrono::system_clock::time_point +UserInfoVC::not_before() const +{ + return parsed_cred->not_before; +} + +std::chrono::system_clock::time_point +UserInfoVC::not_after() const +{ + return parsed_cred->not_after; +} + +const Signature::PublicJWK& +UserInfoVC::public_key() const +{ + return parsed_cred->public_key; +} + +bool +operator==(const UserInfoVC& lhs, const UserInfoVC& rhs) +{ + return lhs.raw == rhs.raw; +} + +} // namespace mlspp::hpke diff --git a/mlspp/lib/mls_vectors/CMakeLists.txt b/mlspp/lib/mls_vectors/CMakeLists.txt new file mode 100755 index 0000000000..e5700b2d00 --- /dev/null +++ b/mlspp/lib/mls_vectors/CMakeLists.txt @@ -0,0 +1,24 @@ +set(CURRENT_LIB_NAME mls_vectors) + +### +### Library Config +### + +file(GLOB_RECURSE LIB_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +add_library(${CURRENT_LIB_NAME} STATIC ${LIB_HEADERS} ${LIB_SOURCES}) +add_dependencies(${CURRENT_LIB_NAME} mlspp) +target_link_libraries(${CURRENT_LIB_NAME} mlspp bytes tls_syntax) +target_include_directories(${CURRENT_LIB_NAME} + PUBLIC + $ + $ + $ +) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/bytes/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/hpke/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/mls_vectors/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/tls_syntax/include") + diff --git a/mlspp/lib/mls_vectors/include/mls_vectors/mls_vectors.h b/mlspp/lib/mls_vectors/include/mls_vectors/mls_vectors.h new file mode 100755 index 0000000000..25c148a94d --- /dev/null +++ b/mlspp/lib/mls_vectors/include/mls_vectors/mls_vectors.h @@ -0,0 +1,577 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mls_vectors { + +struct PseudoRandom +{ + struct Generator + { + Generator() = default; + Generator(mlspp::CipherSuite suite_in, const std::string& label); + Generator sub(const std::string& label) const; + + bytes secret(const std::string& label) const; + bytes generate(const std::string& label, size_t size) const; + + uint16_t uint16(const std::string& label) const; + uint32_t uint32(const std::string& label) const; + uint64_t uint64(const std::string& label) const; + + mlspp::SignaturePrivateKey signature_key( + const std::string& label) const; + mlspp::HPKEPrivateKey hpke_key(const std::string& label) const; + + size_t output_length() const; + + private: + mlspp::CipherSuite suite; + bytes seed; + + Generator(mlspp::CipherSuite suite_in, bytes seed_in); + }; + + PseudoRandom() = default; + PseudoRandom(mlspp::CipherSuite suite, const std::string& label); + + Generator prg; +}; + +struct TreeMathTestVector +{ + using OptionalNode = std::optional; + + mlspp::LeafCount n_leaves; + mlspp::NodeCount n_nodes; + mlspp::NodeIndex root; + std::vector left; + std::vector right; + std::vector parent; + std::vector sibling; + + std::optional null_if_invalid( + mlspp::NodeIndex input, + mlspp::NodeIndex answer) const; + + TreeMathTestVector() = default; + TreeMathTestVector(uint32_t n_leaves); + std::optional verify() const; +}; + +struct CryptoBasicsTestVector : PseudoRandom +{ + struct RefHash + { + std::string label; + bytes value; + bytes out; + + RefHash() = default; + RefHash(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct ExpandWithLabel + { + bytes secret; + std::string label; + bytes context; + uint16_t length; + bytes out; + + ExpandWithLabel() = default; + ExpandWithLabel(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct DeriveSecret + { + bytes secret; + std::string label; + bytes out; + + DeriveSecret() = default; + DeriveSecret(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct DeriveTreeSecret + { + bytes secret; + std::string label; + uint32_t generation; + uint16_t length; + bytes out; + + DeriveTreeSecret() = default; + DeriveTreeSecret(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct SignWithLabel + { + mlspp::SignaturePrivateKey priv; + mlspp::SignaturePublicKey pub; + bytes content; + std::string label; + bytes signature; + + SignWithLabel() = default; + SignWithLabel(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct EncryptWithLabel + { + mlspp::HPKEPrivateKey priv; + mlspp::HPKEPublicKey pub; + std::string label; + bytes context; + bytes plaintext; + bytes kem_output; + bytes ciphertext; + + EncryptWithLabel() = default; + EncryptWithLabel(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + mlspp::CipherSuite cipher_suite; + + RefHash ref_hash; + ExpandWithLabel expand_with_label; + DeriveSecret derive_secret; + DeriveTreeSecret derive_tree_secret; + SignWithLabel sign_with_label; + EncryptWithLabel encrypt_with_label; + + CryptoBasicsTestVector() = default; + CryptoBasicsTestVector(mlspp::CipherSuite suite); + std::optional verify() const; +}; + +struct SecretTreeTestVector : PseudoRandom +{ + struct SenderData + { + bytes sender_data_secret; + bytes ciphertext; + bytes key; + bytes nonce; + + SenderData() = default; + SenderData(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg); + std::optional verify(mlspp::CipherSuite suite) const; + }; + + struct RatchetStep + { + uint32_t generation; + bytes handshake_key; + bytes handshake_nonce; + bytes application_key; + bytes application_nonce; + }; + + mlspp::CipherSuite cipher_suite; + + SenderData sender_data; + + bytes encryption_secret; + std::vector> leaves; + + SecretTreeTestVector() = default; + SecretTreeTestVector(mlspp::CipherSuite suite, + uint32_t n_leaves, + const std::vector& generations); + std::optional verify() const; +}; + +struct KeyScheduleTestVector : PseudoRandom +{ + struct Export + { + std::string label; + bytes context; + size_t length; + bytes secret; + }; + + struct Epoch + { + // Chosen by the generator + bytes tree_hash; + bytes commit_secret; + bytes psk_secret; + bytes confirmed_transcript_hash; + + // Computed values + bytes group_context; + + bytes joiner_secret; + bytes welcome_secret; + bytes init_secret; + + bytes sender_data_secret; + bytes encryption_secret; + bytes exporter_secret; + bytes epoch_authenticator; + bytes external_secret; + bytes confirmation_key; + bytes membership_key; + bytes resumption_psk; + + mlspp::HPKEPublicKey external_pub; + Export exporter; + }; + + mlspp::CipherSuite cipher_suite; + + bytes group_id; + bytes initial_init_secret; + + std::vector epochs; + + KeyScheduleTestVector() = default; + KeyScheduleTestVector(mlspp::CipherSuite suite, uint32_t n_epochs); + std::optional verify() const; +}; + +struct MessageProtectionTestVector : PseudoRandom +{ + mlspp::CipherSuite cipher_suite; + + bytes group_id; + mlspp::epoch_t epoch; + bytes tree_hash; + bytes confirmed_transcript_hash; + + mlspp::SignaturePrivateKey signature_priv; + mlspp::SignaturePublicKey signature_pub; + + bytes encryption_secret; + bytes sender_data_secret; + bytes membership_key; + + mlspp::Proposal proposal; + mlspp::MLSMessage proposal_pub; + mlspp::MLSMessage proposal_priv; + + mlspp::Commit commit; + mlspp::MLSMessage commit_pub; + mlspp::MLSMessage commit_priv; + + bytes application; + mlspp::MLSMessage application_priv; + + MessageProtectionTestVector() = default; + MessageProtectionTestVector(mlspp::CipherSuite suite); + std::optional verify(); + +private: + mlspp::GroupKeySource group_keys() const; + mlspp::GroupContext group_context() const; + + mlspp::MLSMessage protect_pub( + const mlspp::GroupContent::RawContent& raw_content) const; + mlspp::MLSMessage protect_priv( + const mlspp::GroupContent::RawContent& raw_content); + std::optional unprotect( + const mlspp::MLSMessage& message); +}; + +struct PSKSecretTestVector : PseudoRandom +{ + struct PSK + { + bytes psk_id; + bytes psk_nonce; + bytes psk; + }; + + mlspp::CipherSuite cipher_suite; + std::vector psks; + bytes psk_secret; + + PSKSecretTestVector() = default; + PSKSecretTestVector(mlspp::CipherSuite suite, size_t n_psks); + std::optional verify() const; +}; + +struct TranscriptTestVector : PseudoRandom +{ + mlspp::CipherSuite cipher_suite; + + bytes confirmation_key; + bytes interim_transcript_hash_before; + + mlspp::AuthenticatedContent authenticated_content; + + bytes confirmed_transcript_hash_after; + bytes interim_transcript_hash_after; + + TranscriptTestVector() = default; + TranscriptTestVector(mlspp::CipherSuite suite); + std::optional verify() const; +}; + +struct WelcomeTestVector : PseudoRandom +{ + mlspp::CipherSuite cipher_suite; + + mlspp::HPKEPrivateKey init_priv; + mlspp::SignaturePublicKey signer_pub; + + mlspp::MLSMessage key_package; + mlspp::MLSMessage welcome; + + WelcomeTestVector() = default; + WelcomeTestVector(mlspp::CipherSuite suite); + std::optional verify() const; +}; + +// XXX(RLB): The |structure| of the example trees below is to avoid compile +// errors from gcc's -Werror=comment when there is a '\' character at the end of +// a line. Inspired by a similar bug in Chromium: +// https://codereview.chromium.org/874663003/patch/1/10001 +enum struct TreeStructure +{ + // Full trees on N leaves, created by member k adding member k+1 + full_tree_2, + full_tree_3, + full_tree_4, + full_tree_5, + full_tree_6, + full_tree_7, + full_tree_8, + full_tree_32, + full_tree_33, + full_tree_34, + + // | W | + // | ______|______ | + // | / \ | + // | U Y | + // | __|__ __|__ | + // | / \ / \ | + // | T _ X Z | + // | / \ / \ / \ / \ | + // | A B C _ E F G H | + // + // * Start with full tree on 8 members + // * 0 commits removeing 2 and 3, and adding a new member + internal_blanks_no_skipping, + + // | W | + // | ______|______ | + // | / \ | + // | _ Y | + // | __|__ __|__ | + // | / \ / \ | + // | _ _ X Z | + // | / \ / \ / \ / \ | + // | A _ _ _ E F G H | + // + // * Start with full tree on 8 members + // * 0 commitsremoveing 1, 2, and 3 + internal_blanks_with_skipping, + + // | W[H] | + // | ______|______ | + // | / \ | + // | U Y[H] | + // | __|__ __|__ | + // | / \ / \ | + // | T V X _ | + // | / \ / \ / \ / \ | + // | A B C D E F G H | + // + // * Start with full tree on 7 members + // * 0 commits adding a member in a partial Commit (no path) + unmerged_leaves_no_skipping, + + // | W [F] | + // | ______|______ | + // | / \ | + // | U Y [F] | + // | __|__ __|__ | + // | / \ / \ | + // | T _ _ _ | + // | / \ / \ / \ / \ | + // | A B C D E F G _ | + // + // == Fig. 20 / {{parent-hash-tree}} + // * 0 creates group + // * 0 adds 1, ..., 6 in a partial Commit + // * O commits removing 5 + // * 4 commits without any proposals + // * 0 commits adding a new member in a partial Commit + unmerged_leaves_with_skipping, +}; + +extern std::array all_tree_structures; +extern std::array treekem_test_tree_structures; + +struct TreeHashTestVector : PseudoRandom +{ + mlspp::CipherSuite cipher_suite; + bytes group_id; + + mlspp::TreeKEMPublicKey tree; + std::vector tree_hashes; + std::vector> resolutions; + + TreeHashTestVector() = default; + TreeHashTestVector(mlspp::CipherSuite suite, + TreeStructure tree_structure); + std::optional verify(); +}; + +struct TreeOperationsTestVector : PseudoRandom +{ + enum struct Scenario + { + add_right_edge, + add_internal, + update, + remove_right_edge, + remove_internal, + }; + + static const std::vector all_scenarios; + + mlspp::CipherSuite cipher_suite; + + mlspp::TreeKEMPublicKey tree_before; + bytes tree_hash_before; + + mlspp::Proposal proposal; + mlspp::LeafIndex proposal_sender; + + mlspp::TreeKEMPublicKey tree_after; + bytes tree_hash_after; + + TreeOperationsTestVector() = default; + TreeOperationsTestVector(mlspp::CipherSuite suite, Scenario scenario); + std::optional verify(); +}; + +struct TreeKEMTestVector : PseudoRandom +{ + struct PathSecret + { + mlspp::NodeIndex node; + bytes path_secret; + }; + + struct LeafPrivateInfo + { + mlspp::LeafIndex index; + mlspp::HPKEPrivateKey encryption_priv; + mlspp::SignaturePrivateKey signature_priv; + std::vector path_secrets; + }; + + struct UpdatePathInfo + { + mlspp::LeafIndex sender; + mlspp::UpdatePath update_path; + std::vector> path_secrets; + bytes commit_secret; + bytes tree_hash_after; + }; + + mlspp::CipherSuite cipher_suite; + + bytes group_id; + mlspp::epoch_t epoch; + bytes confirmed_transcript_hash; + + mlspp::TreeKEMPublicKey ratchet_tree; + + std::vector leaves_private; + std::vector update_paths; + + TreeKEMTestVector() = default; + TreeKEMTestVector(mlspp::CipherSuite suite, + TreeStructure tree_structure); + std::optional verify(); +}; + +struct MessagesTestVector : PseudoRandom +{ + bytes mls_welcome; + bytes mls_group_info; + bytes mls_key_package; + + bytes ratchet_tree; + bytes group_secrets; + + bytes add_proposal; + bytes update_proposal; + bytes remove_proposal; + bytes pre_shared_key_proposal; + bytes re_init_proposal; + bytes external_init_proposal; + bytes group_context_extensions_proposal; + + bytes commit; + + bytes public_message_proposal; + bytes public_message_commit; + bytes private_message; + + MessagesTestVector(); + std::optional verify() const; +}; + +struct PassiveClientTestVector : PseudoRandom +{ + struct PSK + { + bytes psk_id; + bytes psk; + }; + + struct Epoch + { + std::vector proposals; + mlspp::MLSMessage commit; + bytes epoch_authenticator; + }; + + mlspp::CipherSuite cipher_suite; + + mlspp::MLSMessage key_package; + mlspp::SignaturePrivateKey signature_priv; + mlspp::HPKEPrivateKey encryption_priv; + mlspp::HPKEPrivateKey init_priv; + + std::vector external_psks; + + mlspp::MLSMessage welcome; + std::optional ratchet_tree; + bytes initial_epoch_authenticator; + + std::vector epochs; + + PassiveClientTestVector() = default; + std::optional verify(); +}; + +} // namespace mls_vectors diff --git a/mlspp/lib/mls_vectors/src/mls_vectors.cpp b/mlspp/lib/mls_vectors/src/mls_vectors.cpp new file mode 100755 index 0000000000..a6176efa55 --- /dev/null +++ b/mlspp/lib/mls_vectors/src/mls_vectors.cpp @@ -0,0 +1,2052 @@ +#include +#include +#include +#include + +#include // XXX + +namespace mls_vectors { + +using namespace mlspp; + +/// +/// Assertions for verifying test vectors +/// + +template, int> = 0> +std::ostream& +operator<<(std::ostream& str, const T& obj) +{ + auto u = static_cast>(obj); + return str << u; +} + +static std::ostream& +operator<<(std::ostream& str, const NodeIndex& obj) +{ + return str << obj.val; +} + +static std::ostream& +operator<<(std::ostream& str, const NodeCount& obj) +{ + return str << obj.val; +} + +template +static std::ostream& +operator<<(std::ostream& str, const std::optional& obj) +{ + if (!obj) { + return str << "(nullopt)"; + } + + return str << opt::get(obj); +} + +static std::ostream& +operator<<(std::ostream& str, const std::vector& obj) +{ + return str << to_hex(obj); +} + +template +static std::ostream& +operator<<(std::ostream& str, const std::vector& obj) +{ + for (const auto& val : obj) { + str << val << " "; + } + return str; +} + +static std::ostream& +operator<<(std::ostream& str, const GroupContent::RawContent& obj) +{ + return var::visit( + overloaded{ + [&](const Proposal&) -> std::ostream& { return str << "[Proposal]"; }, + [&](const Commit&) -> std::ostream& { return str << "[Commit]"; }, + [&](const ApplicationData&) -> std::ostream& { + return str << "[ApplicationData]"; + }, + }, + obj); +} + +template +inline std::enable_if_t +operator<<(std::ostream& str, const T& obj) +{ + return str << to_hex(tls::marshal(obj)); +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERIFY(label, test) \ + if (auto err = verify_bool(label, test)) { \ + return err; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERIFY_EQUAL(label, actual, expected) \ + if (auto err = verify_equal(label, actual, expected)) { \ + return err; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERIFY_TLS_RTT(label, Type, expected) \ + if (auto err = verify_round_trip(label, expected)) { \ + return err; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VERIFY_TLS_RTT_VAL(label, Type, expected, val) \ + if (auto err = verify_round_trip(label, expected, val)) { \ + return err; \ + } + +template +static std::optional +verify_bool(const std::string& label, const T& test) +{ + if (test) { + return std::nullopt; + } + + return label; +} + +template +static std::optional +verify_equal(const std::string& label, const T& actual, const U& expected) +{ + if (actual == expected) { + return std::nullopt; + } + + auto ss = std::stringstream(); + ss << "Error: " << label << " " << actual << " != " << expected; + return ss.str(); +} + +template +static std::optional +verify_round_trip(const std::string& label, const bytes& expected) +{ + auto noop = [](const auto& /* unused */) { return true; }; + return verify_round_trip(label, expected, noop); +} + +template +static std::optional +verify_round_trip(const std::string& label, const bytes& expected, const F& val) +{ + auto obj = T{}; + try { + obj = tls::get(expected); + } catch (const std::exception& e) { + auto ss = std::stringstream(); + ss << "Decode error: " << label << " " << e.what(); + return ss.str(); + } + + if (!val(obj)) { + auto ss = std::stringstream(); + ss << "Validation error: " << label; + return ss.str(); + } + + auto actual = tls::marshal(obj); + VERIFY_EQUAL(label, actual, expected); + return std::nullopt; +} + +/// +/// PseudoRandom +/// + +PseudoRandom::Generator::Generator(CipherSuite suite_in, + const std::string& label) + : suite(suite_in) + , seed(suite.hpke().kdf.extract({}, from_ascii(label))) +{ +} + +PseudoRandom::Generator::Generator(CipherSuite suite_in, bytes seed_in) + : suite(suite_in) + , seed(std::move(seed_in)) +{ +} + +PseudoRandom::Generator +PseudoRandom::Generator::sub(const std::string& label) const +{ + return { suite, suite.derive_secret(seed, label) }; +} + +bytes +PseudoRandom::Generator::secret(const std::string& label) const +{ + return suite.derive_secret(seed, label); +} + +bytes +PseudoRandom::Generator::generate(const std::string& label, size_t size) const +{ + return suite.expand_with_label(seed, label, {}, size); +} + +uint16_t +PseudoRandom::Generator::uint16(const std::string& label) const +{ + auto data = generate(label, 2); + return tls::get(data); +} + +uint32_t +PseudoRandom::Generator::uint32(const std::string& label) const +{ + auto data = generate(label, 4); + return tls::get(data); +} + +uint64_t +PseudoRandom::Generator::uint64(const std::string& label) const +{ + auto data = generate(label, 8); + return tls::get(data); +} + +SignaturePrivateKey +PseudoRandom::Generator::signature_key(const std::string& label) const +{ + auto data = generate(label, suite.secret_size()); + return SignaturePrivateKey::derive(suite, data); +} + +HPKEPrivateKey +PseudoRandom::Generator::hpke_key(const std::string& label) const +{ + auto data = generate(label, suite.secret_size()); + return HPKEPrivateKey::derive(suite, data); +} + +size_t +PseudoRandom::Generator::output_length() const +{ + return suite.secret_size(); +} + +PseudoRandom::PseudoRandom(CipherSuite suite, const std::string& label) + : prg(suite, label) +{ +} + +/// +/// TreeMathTestVector +/// + +// XXX(RLB): This is a hack to get the tests working in the right format. In +// reality, the tree math functions should be updated to be fallible. +std::optional +TreeMathTestVector::null_if_invalid(NodeIndex input, NodeIndex answer) const +{ + // For some invalid cases (e.g., leaf.left()), we currently return the node + // itself instead of null + if (input == answer) { + return std::nullopt; + } + + // NodeIndex::parent is irrespective of tree size, so we might step out of the + // tree under consideration. + if (answer.val >= n_nodes.val) { + return std::nullopt; + } + + return answer; +} + +TreeMathTestVector::TreeMathTestVector(uint32_t n_leaves_in) + : n_leaves(n_leaves_in) + , n_nodes(n_leaves) + , root(NodeIndex::root(n_leaves)) + , left(n_nodes.val) + , right(n_nodes.val) + , parent(n_nodes.val) + , sibling(n_nodes.val) +{ + for (NodeIndex x{ 0 }; x.val < n_nodes.val; x.val++) { + left[x.val] = null_if_invalid(x, x.left()); + right[x.val] = null_if_invalid(x, x.right()); + parent[x.val] = null_if_invalid(x, x.parent()); + sibling[x.val] = null_if_invalid(x, x.sibling()); + } +} + +std::optional +TreeMathTestVector::verify() const +{ + VERIFY_EQUAL("n_nodes", n_nodes, NodeCount(n_leaves)); + VERIFY_EQUAL("root", root, NodeIndex::root(n_leaves)); + + for (NodeIndex x{ 0 }; x.val < n_nodes.val; x.val++) { + VERIFY_EQUAL("left", null_if_invalid(x, x.left()), left[x.val]); + VERIFY_EQUAL("right", null_if_invalid(x, x.right()), right[x.val]); + VERIFY_EQUAL("parent", null_if_invalid(x, x.parent()), parent[x.val]); + VERIFY_EQUAL("sibling", null_if_invalid(x, x.sibling()), sibling[x.val]); + } + + return std::nullopt; +} + +/// +/// TreeMathTestVector +/// + +CryptoBasicsTestVector::RefHash::RefHash(CipherSuite suite, + const PseudoRandom::Generator& prg) + : label("RefHash") + , value(prg.secret("value")) + , out(suite.raw_ref(from_ascii(label), value)) +{ +} + +std::optional +CryptoBasicsTestVector::RefHash::verify(CipherSuite suite) const +{ + VERIFY_EQUAL("ref hash", out, suite.raw_ref(from_ascii(label), value)); + return std::nullopt; +} + +CryptoBasicsTestVector::ExpandWithLabel::ExpandWithLabel( + CipherSuite suite, + const PseudoRandom::Generator& prg) + : secret(prg.secret("secret")) + , label("ExpandWithLabel") + , context(prg.secret("context")) + , length(static_cast(prg.output_length())) + , out(suite.expand_with_label(secret, label, context, length)) +{ +} + +std::optional +CryptoBasicsTestVector::ExpandWithLabel::verify(CipherSuite suite) const +{ + VERIFY_EQUAL("expand with label", + out, + suite.expand_with_label(secret, label, context, length)); + return std::nullopt; +} + +CryptoBasicsTestVector::DeriveSecret::DeriveSecret( + CipherSuite suite, + const PseudoRandom::Generator& prg) + : secret(prg.secret("secret")) + , label("DeriveSecret") + , out(suite.derive_secret(secret, label)) +{ +} + +std::optional +CryptoBasicsTestVector::DeriveSecret::verify(CipherSuite suite) const +{ + VERIFY_EQUAL("derive secret", out, suite.derive_secret(secret, label)); + return std::nullopt; +} + +CryptoBasicsTestVector::DeriveTreeSecret::DeriveTreeSecret( + CipherSuite suite, + const PseudoRandom::Generator& prg) + : secret(prg.secret("secret")) + , label("DeriveTreeSecret") + , generation(prg.uint32("generation")) + , length(static_cast(prg.output_length())) + , out(suite.derive_tree_secret(secret, label, generation, length)) +{ +} + +std::optional +CryptoBasicsTestVector::DeriveTreeSecret::verify(CipherSuite suite) const +{ + VERIFY_EQUAL("derive tree secret", + out, + suite.derive_tree_secret(secret, label, generation, length)); + return std::nullopt; +} + +CryptoBasicsTestVector::SignWithLabel::SignWithLabel( + CipherSuite suite, + const PseudoRandom::Generator& prg) + : priv(prg.signature_key("priv")) + , pub(priv.public_key) + , content(prg.secret("content")) + , label("SignWithLabel") + , signature(priv.sign(suite, label, content)) +{ +} + +std::optional +CryptoBasicsTestVector::SignWithLabel::verify(CipherSuite suite) const +{ + VERIFY("verify with label", pub.verify(suite, label, content, signature)); + + auto new_signature = priv.sign(suite, label, content); + VERIFY("sign with label", pub.verify(suite, label, content, new_signature)); + + return std::nullopt; +} + +CryptoBasicsTestVector::EncryptWithLabel::EncryptWithLabel( + CipherSuite suite, + const PseudoRandom::Generator& prg) + : priv(prg.hpke_key("priv")) + , pub(priv.public_key) + , label("EncryptWithLabel") + , context(prg.secret("context")) + , plaintext(prg.secret("plaintext")) +{ + auto ct = pub.encrypt(suite, label, context, plaintext); + kem_output = ct.kem_output; + ciphertext = ct.ciphertext; +} + +std::optional +CryptoBasicsTestVector::EncryptWithLabel::verify(CipherSuite suite) const +{ + auto ct = HPKECiphertext{ kem_output, ciphertext }; + auto pt = priv.decrypt(suite, label, context, ct); + VERIFY_EQUAL("decrypt with label", pt, plaintext); + + auto new_ct = pub.encrypt(suite, label, context, plaintext); + auto new_pt = priv.decrypt(suite, label, context, new_ct); + VERIFY_EQUAL("encrypt with label", new_pt, plaintext); + + return std::nullopt; +} + +CryptoBasicsTestVector::CryptoBasicsTestVector(CipherSuite suite) + : PseudoRandom(suite, "crypto-basics") + , cipher_suite(suite) + , ref_hash(suite, prg.sub("ref_hash")) + , expand_with_label(suite, prg.sub("expand_with_label")) + , derive_secret(suite, prg.sub("derive_secret")) + , derive_tree_secret(suite, prg.sub("derive_tree_secret")) + , sign_with_label(suite, prg.sub("sign_with_label")) + , encrypt_with_label(suite, prg.sub("encrypt_with_label")) +{ +} + +std::optional +CryptoBasicsTestVector::verify() const +{ + auto result = ref_hash.verify(cipher_suite); + if (result) { + return result; + } + + result = expand_with_label.verify(cipher_suite); + if (result) { + return result; + } + + result = derive_secret.verify(cipher_suite); + if (result) { + return result; + } + + result = derive_tree_secret.verify(cipher_suite); + if (result) { + return result; + } + + result = sign_with_label.verify(cipher_suite); + if (result) { + return result; + } + + result = encrypt_with_label.verify(cipher_suite); + if (result) { + return result; + } + + return std::nullopt; +} + +/// +/// SecretTreeTestVector +/// + +SecretTreeTestVector::SenderData::SenderData(mlspp::CipherSuite suite, + const PseudoRandom::Generator& prg) + : sender_data_secret(prg.secret("sender_data_secret")) + , ciphertext(prg.secret("ciphertext")) +{ + auto key_and_nonce = + KeyScheduleEpoch::sender_data_keys(suite, sender_data_secret, ciphertext); + key = key_and_nonce.key; + nonce = key_and_nonce.nonce; +} + +std::optional +SecretTreeTestVector::SenderData::verify(mlspp::CipherSuite suite) const +{ + auto key_and_nonce = + KeyScheduleEpoch::sender_data_keys(suite, sender_data_secret, ciphertext); + VERIFY_EQUAL("sender data key", key, key_and_nonce.key); + VERIFY_EQUAL("sender data nonce", nonce, key_and_nonce.nonce); + return std::nullopt; +} + +SecretTreeTestVector::SecretTreeTestVector( + mlspp::CipherSuite suite, + uint32_t n_leaves, + const std::vector& generations) + : PseudoRandom(suite, "secret-tree") + , cipher_suite(suite) + , sender_data(suite, prg.sub("sender_data")) + , encryption_secret(prg.secret("encryption_secret")) +{ + auto src = + GroupKeySource(cipher_suite, LeafCount{ n_leaves }, encryption_secret); + leaves.resize(n_leaves); + auto zero_reuse_guard = ReuseGuard{ 0, 0, 0, 0 }; + for (uint32_t i = 0; i < n_leaves; i++) { + auto leaf = LeafIndex{ i }; + + for (const auto generation : generations) { + auto hs = + src.get(ContentType::proposal, leaf, generation, zero_reuse_guard); + auto app = + src.get(ContentType::application, leaf, generation, zero_reuse_guard); + + leaves.at(i).push_back( + RatchetStep{ generation, hs.key, hs.nonce, app.key, app.nonce }); + + src.erase(ContentType::proposal, leaf, generation); + src.erase(ContentType::application, leaf, generation); + } + } +} + +std::optional +SecretTreeTestVector::verify() const +{ + auto sender_data_error = sender_data.verify(cipher_suite); + if (sender_data_error) { + return sender_data_error; + } + + auto n_leaves = static_cast(leaves.size()); + auto src = + GroupKeySource(cipher_suite, LeafCount{ n_leaves }, encryption_secret); + auto zero_reuse_guard = ReuseGuard{ 0, 0, 0, 0 }; + for (uint32_t i = 0; i < n_leaves; i++) { + auto leaf = LeafIndex{ i }; + + for (const auto& step : leaves[i]) { + auto generation = step.generation; + + auto hs = + src.get(ContentType::proposal, leaf, generation, zero_reuse_guard); + VERIFY_EQUAL("hs key", hs.key, step.handshake_key); + VERIFY_EQUAL("hs nonce", hs.nonce, step.handshake_nonce); + + auto app = + src.get(ContentType::application, leaf, generation, zero_reuse_guard); + VERIFY_EQUAL("app key", app.key, step.application_key); + VERIFY_EQUAL("app nonce", app.nonce, step.application_nonce); + } + } + + return std::nullopt; +} + +/// +/// KeyScheduleTestVector +/// + +KeyScheduleTestVector::KeyScheduleTestVector(CipherSuite suite, + uint32_t n_epochs) + : PseudoRandom(suite, "key-schedule") + , cipher_suite(suite) + , group_id(prg.secret("group_id")) + , initial_init_secret(prg.secret("group_id")) +{ + auto group_context = GroupContext{ suite, group_id, 0, {}, {}, {} }; + auto epoch = KeyScheduleEpoch(cipher_suite); + epoch.init_secret = initial_init_secret; + + for (uint64_t i = 0; i < n_epochs; i++) { + auto epoch_prg = prg.sub(to_hex(tls::marshal(i))); + + group_context.tree_hash = epoch_prg.secret("tree_hash"); + group_context.confirmed_transcript_hash = + epoch_prg.secret("confirmed_transcript_hash"); + auto ctx = tls::marshal(group_context); + + // TODO(RLB) Add Test case for externally-driven epoch change + auto commit_secret = epoch_prg.secret("commit_secret"); + auto psk_secret = epoch_prg.secret("psk_secret"); + epoch = epoch.next_raw(commit_secret, psk_secret, std::nullopt, ctx); + + auto welcome_secret = KeyScheduleEpoch::welcome_secret_raw( + cipher_suite, epoch.joiner_secret, psk_secret); + + auto exporter_prg = epoch_prg.sub("exporter"); + auto exporter_label = to_hex(exporter_prg.secret("label")); + auto exporter_context = exporter_prg.secret("context"); + auto exporter_length = cipher_suite.secret_size(); + auto exported = + epoch.do_export(exporter_label, exporter_context, exporter_length); + + epochs.push_back({ group_context.tree_hash, + commit_secret, + psk_secret, + group_context.confirmed_transcript_hash, + + ctx, + + epoch.joiner_secret, + welcome_secret, + epoch.init_secret, + + epoch.sender_data_secret, + epoch.encryption_secret, + epoch.exporter_secret, + epoch.epoch_authenticator, + epoch.external_secret, + epoch.confirmation_key, + epoch.membership_key, + epoch.resumption_psk, + + epoch.external_priv.public_key, + + { + exporter_label, + exporter_context, + exporter_length, + exported, + } }); + + group_context.epoch += 1; + } +} + +std::optional +KeyScheduleTestVector::verify() const +{ + auto group_context = GroupContext{ cipher_suite, group_id, 0, {}, {}, {} }; + auto epoch = KeyScheduleEpoch(cipher_suite); + epoch.init_secret = initial_init_secret; + + for (const auto& tve : epochs) { + group_context.tree_hash = tve.tree_hash; + group_context.confirmed_transcript_hash = tve.confirmed_transcript_hash; + auto ctx = tls::marshal(group_context); + VERIFY_EQUAL("group context", ctx, tve.group_context); + + epoch = + epoch.next_raw(tve.commit_secret, tve.psk_secret, std::nullopt, ctx); + + // Verify the rest of the epoch + VERIFY_EQUAL("joiner secret", epoch.joiner_secret, tve.joiner_secret); + + auto welcome_secret = KeyScheduleEpoch::welcome_secret_raw( + cipher_suite, tve.joiner_secret, tve.psk_secret); + VERIFY_EQUAL("welcome secret", welcome_secret, tve.welcome_secret); + + VERIFY_EQUAL( + "sender data secret", epoch.sender_data_secret, tve.sender_data_secret); + VERIFY_EQUAL( + "encryption secret", epoch.encryption_secret, tve.encryption_secret); + VERIFY_EQUAL("exporter secret", epoch.exporter_secret, tve.exporter_secret); + VERIFY_EQUAL("epoch authenticator", + epoch.epoch_authenticator, + tve.epoch_authenticator); + VERIFY_EQUAL("external secret", epoch.external_secret, tve.external_secret); + VERIFY_EQUAL( + "confirmation key", epoch.confirmation_key, tve.confirmation_key); + VERIFY_EQUAL("membership key", epoch.membership_key, tve.membership_key); + VERIFY_EQUAL("resumption psk", epoch.resumption_psk, tve.resumption_psk); + VERIFY_EQUAL("init secret", epoch.init_secret, tve.init_secret); + + VERIFY_EQUAL( + "external pub", epoch.external_priv.public_key, tve.external_pub); + + auto exported = epoch.do_export( + tve.exporter.label, tve.exporter.context, tve.exporter.length); + VERIFY_EQUAL("exported", exported, tve.exporter.secret); + + group_context.epoch += 1; + } + + return std::nullopt; +} + +/// +/// MessageProtectionTestVector +/// + +MessageProtectionTestVector::MessageProtectionTestVector(CipherSuite suite) + : PseudoRandom(suite, "message-protection") + , cipher_suite(suite) + , group_id(prg.secret("group_id")) + , epoch(prg.uint64("epoch")) + , tree_hash(prg.secret("tree_hash")) + , confirmed_transcript_hash(prg.secret("confirmed_transcript_hash")) + , signature_priv(prg.signature_key("signature_priv")) + , signature_pub(signature_priv.public_key) + , encryption_secret(prg.secret("encryption_secret")) + , sender_data_secret(prg.secret("sender_data_secret")) + , membership_key(prg.secret("membership_key")) + , proposal{ GroupContextExtensions{} } + , commit{ /* XXX(RLB) this is technically invalid, empty w/o path */ } + , application{ prg.secret("application") } +{ + proposal_pub = protect_pub(proposal); + proposal_priv = protect_priv(proposal); + + commit_pub = protect_pub(commit); + commit_priv = protect_priv(commit); + + application_priv = protect_priv(ApplicationData{ application }); +} + +std::optional +MessageProtectionTestVector::verify() +{ + // Initialize fields that don't get set from JSON + prg = PseudoRandom::Generator(cipher_suite, "message-protection"); + signature_priv.set_public_key(cipher_suite); + + // Sanity check the key pairs + VERIFY_EQUAL("sig kp", signature_priv.public_key, signature_pub); + + // Verify proposal unprotect as PublicMessage + auto proposal_pub_unprotected = unprotect(proposal_pub); + VERIFY("proposal pub unprotect auth", proposal_pub_unprotected); + VERIFY_EQUAL("proposal pub unprotect", + opt::get(proposal_pub_unprotected).content, + proposal); + + // Verify proposal unprotect as PrivateMessage + auto proposal_priv_unprotected = unprotect(proposal_priv); + VERIFY("proposal priv unprotect auth", proposal_priv_unprotected); + VERIFY_EQUAL("proposal priv unprotect", + opt::get(proposal_priv_unprotected).content, + proposal); + + // Verify commit unprotect as PublicMessage + auto commit_pub_unprotected = unprotect(commit_pub); + VERIFY("commit pub unprotect auth", commit_pub_unprotected); + VERIFY_EQUAL( + "commit pub unprotect", opt::get(commit_pub_unprotected).content, commit); + + // Verify commit unprotect as PrivateMessage + auto commit_priv_unprotected = unprotect(commit_priv); + VERIFY("commit priv unprotect auth", commit_priv_unprotected); + VERIFY_EQUAL( + "commit priv unprotect", opt::get(commit_priv_unprotected).content, commit); + + // Verify application data unprotect as PrivateMessage + auto app_unprotected = unprotect(application_priv); + VERIFY("app priv unprotect auth", app_unprotected); + VERIFY_EQUAL("app priv unprotect", + opt::get(app_unprotected).content, + ApplicationData{ application }); + + // Verify protect/unprotect round-trips + // XXX(RLB): Note that because (a) unprotect() deletes keys from the ratchet + // and (b) we are using the same ratchet to send and receive, we need to do + // these round-trip tests after all the unprotect tests are done. Otherwise + // the protect() calls here will re-use generations used the test vector, and + // then unprotect() will delete the keys, then when you go to decrypt the test + // vector object, you'll get "expired key". It might be good to have better + // safeguards around such reuse. + auto proposal_pub_protected = protect_pub(proposal); + auto proposal_pub_protected_unprotected = unprotect(proposal_pub_protected); + VERIFY("proposal pub protect/unprotect auth", + proposal_pub_protected_unprotected); + VERIFY_EQUAL("proposal pub protect/unprotect", + opt::get(proposal_pub_protected_unprotected).content, + proposal); + + auto proposal_priv_protected = protect_priv(proposal); + auto proposal_priv_protected_unprotected = unprotect(proposal_priv_protected); + VERIFY("proposal priv protect/unprotect auth", + proposal_priv_protected_unprotected); + VERIFY_EQUAL("proposal priv protect/unprotect", + opt::get(proposal_priv_protected_unprotected).content, + proposal); + + auto commit_pub_protected = protect_pub(commit); + auto commit_pub_protected_unprotected = unprotect(commit_pub_protected); + VERIFY("commit pub protect/unprotect auth", commit_pub_protected_unprotected); + VERIFY_EQUAL("commit pub protect/unprotect", + opt::get(commit_pub_protected_unprotected).content, + commit); + + auto commit_priv_protected = protect_priv(commit); + auto commit_priv_protected_unprotected = unprotect(commit_priv_protected); + VERIFY("commit priv protect/unprotect auth", + commit_priv_protected_unprotected); + VERIFY_EQUAL("commit priv protect/unprotect", + opt::get(commit_priv_protected_unprotected).content, + commit); + + auto app_protected = protect_priv(ApplicationData{ application }); + auto app_protected_unprotected = unprotect(app_protected); + VERIFY("app priv protect/unprotect auth", app_protected_unprotected); + VERIFY_EQUAL("app priv protect/unprotect", + opt::get(app_protected_unprotected).content, + ApplicationData{ application }); + + return std::nullopt; +} + +GroupKeySource +MessageProtectionTestVector::group_keys() const +{ + return { cipher_suite, LeafCount{ 2 }, encryption_secret }; +} + +GroupContext +MessageProtectionTestVector::group_context() const +{ + return GroupContext{ + cipher_suite, group_id, epoch, tree_hash, confirmed_transcript_hash, {} + }; +} + +MLSMessage +MessageProtectionTestVector::protect_pub( + const mlspp::GroupContent::RawContent& raw_content) const +{ + auto sender = Sender{ MemberSender{ LeafIndex{ 1 } } }; + auto authenticated_data = bytes{}; + + auto content = + GroupContent{ group_id, epoch, sender, authenticated_data, raw_content }; + + auto auth_content = AuthenticatedContent::sign(WireFormat::mls_public_message, + content, + cipher_suite, + signature_priv, + group_context()); + if (content.content_type() == ContentType::commit) { + auto confirmation_tag = prg.secret("confirmation_tag"); + auth_content.set_confirmation_tag(confirmation_tag); + } + + return PublicMessage::protect( + auth_content, cipher_suite, membership_key, group_context()); +} + +MLSMessage +MessageProtectionTestVector::protect_priv( + const mlspp::GroupContent::RawContent& raw_content) +{ + auto sender = Sender{ MemberSender{ LeafIndex{ 1 } } }; + auto authenticated_data = bytes{}; + auto padding_size = size_t(0); + + auto content = + GroupContent{ group_id, epoch, sender, authenticated_data, raw_content }; + + auto auth_content = + AuthenticatedContent::sign(WireFormat::mls_private_message, + content, + cipher_suite, + signature_priv, + group_context()); + if (content.content_type() == ContentType::commit) { + auto confirmation_tag = prg.secret("confirmation_tag"); + auth_content.set_confirmation_tag(confirmation_tag); + } + + auto keys = group_keys(); + return PrivateMessage::protect( + auth_content, cipher_suite, keys, sender_data_secret, padding_size); +} + +std::optional +MessageProtectionTestVector::unprotect(const MLSMessage& message) +{ + auto do_unprotect = + overloaded{ [&](const PublicMessage& pt) { + return pt.unprotect( + cipher_suite, membership_key, group_context()); + }, + [&](const PrivateMessage& ct) { + auto keys = group_keys(); + return ct.unprotect(cipher_suite, keys, sender_data_secret); + }, + [](const auto& /* other */) -> std::optional { + return std::nullopt; + } }; + + auto maybe_auth_content = var::visit(do_unprotect, message.message); + if (!maybe_auth_content) { + return std::nullopt; + } + + auto val_content = opt::get(maybe_auth_content); + const auto& auth_content = val_content.authenticated_content(); + if (!auth_content.verify(cipher_suite, signature_pub, group_context())) { + return std::nullopt; + } + + return auth_content.content; +} + +/// +/// PSKTestVector +/// +static std::vector +to_psk_w_secret(const std::vector& psks) +{ + auto pskws = std::vector(psks.size()); + std::transform( + std::begin(psks), std::end(psks), std::begin(pskws), [](const auto& psk) { + auto ext_id = ExternalPSK{ psk.psk_id }; + auto id = PreSharedKeyID{ ext_id, psk.psk_nonce }; + return PSKWithSecret{ id, psk.psk }; + }); + + return pskws; +} + +PSKSecretTestVector::PSKSecretTestVector(mlspp::CipherSuite suite, + size_t n_psks) + : PseudoRandom(suite, "psk_secret") + , cipher_suite(suite) + , psks(n_psks) +{ + uint32_t i = 0; + for (auto& psk : psks) { + auto ix = to_hex(tls::marshal(i)); + i += 1; + + psk.psk_id = prg.secret("psk_id" + ix); + psk.psk_nonce = prg.secret("psk_nonce" + ix); + psk.psk = prg.secret("psk" + ix); + } + + psk_secret = + KeyScheduleEpoch::make_psk_secret(cipher_suite, to_psk_w_secret(psks)); +} + +std::optional +PSKSecretTestVector::verify() const +{ + auto actual = + KeyScheduleEpoch::make_psk_secret(cipher_suite, to_psk_w_secret(psks)); + VERIFY_EQUAL("psk secret", actual, psk_secret); + + return std::nullopt; +} + +/// +/// TranscriptTestVector +/// +TranscriptTestVector::TranscriptTestVector(CipherSuite suite) + : PseudoRandom(suite, "transcript") + , cipher_suite(suite) + , interim_transcript_hash_before(prg.secret("interim_transcript_hash_before")) +{ + auto transcript = TranscriptHash(suite); + transcript.interim = interim_transcript_hash_before; + + auto group_id = prg.secret("group_id"); + auto epoch = prg.uint64("epoch"); + auto group_context_obj = + GroupContext{ suite, + group_id, + epoch, + prg.secret("tree_hash_before"), + prg.secret("confirmed_transcript_hash_before"), + {} }; + auto group_context = tls::marshal(group_context_obj); + + auto init_secret = prg.secret("init_secret"); + auto ks_epoch = KeyScheduleEpoch(suite, init_secret, group_context); + + auto sig_priv = prg.signature_key("sig_priv"); + auto leaf_index = LeafIndex{ 0 }; + + authenticated_content = AuthenticatedContent::sign( + WireFormat::mls_public_message, + GroupContent{ + group_id, epoch, { MemberSender{ leaf_index } }, {}, Commit{} }, + suite, + sig_priv, + group_context_obj); + + transcript.update_confirmed(authenticated_content); + + const auto confirmation_tag = ks_epoch.confirmation_tag(transcript.confirmed); + authenticated_content.set_confirmation_tag(confirmation_tag); + + transcript.update_interim(authenticated_content); + + // Store the required data + confirmation_key = ks_epoch.confirmation_key; + confirmed_transcript_hash_after = transcript.confirmed; + interim_transcript_hash_after = transcript.interim; +} + +std::optional +TranscriptTestVector::verify() const +{ + auto transcript = TranscriptHash(cipher_suite); + transcript.interim = interim_transcript_hash_before; + + transcript.update(authenticated_content); + VERIFY_EQUAL( + "confirmed", transcript.confirmed, confirmed_transcript_hash_after); + VERIFY_EQUAL("interim", transcript.interim, interim_transcript_hash_after); + + auto confirmation_tag = + cipher_suite.digest().hmac(confirmation_key, transcript.confirmed); + VERIFY_EQUAL("confirmation tag", + confirmation_tag, + authenticated_content.auth.confirmation_tag); + + return std::nullopt; +} + +/// +/// WelcomeTestVector +/// +WelcomeTestVector::WelcomeTestVector(CipherSuite suite) + : PseudoRandom(suite, "welcome") + , cipher_suite(suite) + , init_priv(prg.hpke_key("init_priv")) +{ + auto joiner_secret = prg.secret("joiner_secret"); + auto group_id = prg.secret("group_id"); + auto epoch = epoch_t(prg.uint64("epoch")); + auto tree_hash = prg.secret("tree_hash"); + auto confirmed_transcript_hash = prg.secret("confirmed_transcript_hash"); + auto enc_priv = prg.hpke_key("enc_priv"); + auto sig_priv = prg.signature_key("sig_priv"); + auto cred = Credential::basic(prg.secret("identity")); + + auto signer_index = LeafIndex{ prg.uint32("signer") }; + auto signer_priv = prg.signature_key("signer_priv"); + signer_pub = signer_priv.public_key; + + auto leaf_node = LeafNode{ + cipher_suite, + enc_priv.public_key, + sig_priv.public_key, + cred, + Capabilities::create_default(), + Lifetime::create_default(), + {}, + sig_priv, + }; + auto key_package_obj = KeyPackage{ + cipher_suite, init_priv.public_key, leaf_node, {}, sig_priv, + }; + key_package = key_package_obj; + + auto group_context = GroupContext{ + cipher_suite, group_id, epoch, tree_hash, confirmed_transcript_hash, {} + }; + + auto key_schedule = KeyScheduleEpoch::joiner( + cipher_suite, joiner_secret, {}, tls::marshal(group_context)); + auto confirmation_tag = + key_schedule.confirmation_tag(confirmed_transcript_hash); + + auto group_info = GroupInfo{ + group_context, + {}, + confirmation_tag, + }; + group_info.sign(signer_index, signer_priv); + + auto welcome_obj = Welcome(cipher_suite, joiner_secret, {}, group_info); + welcome_obj.encrypt(key_package_obj, std::nullopt); + welcome = welcome_obj; +} + +std::optional +WelcomeTestVector::verify() const +{ + VERIFY_EQUAL( + "kp format", key_package.wire_format(), WireFormat::mls_key_package); + VERIFY_EQUAL( + "welcome format", welcome.wire_format(), WireFormat::mls_welcome); + + const auto& key_package_obj = var::get(key_package.message); + const auto& welcome_obj = var::get(welcome.message); + + VERIFY_EQUAL("kp suite", key_package_obj.cipher_suite, cipher_suite); + VERIFY_EQUAL("welcome suite", welcome_obj.cipher_suite, cipher_suite); + + auto maybe_kpi = welcome_obj.find(key_package_obj); + VERIFY("found key package", maybe_kpi); + + auto kpi = opt::get(maybe_kpi); + auto group_secrets = welcome_obj.decrypt_secrets(kpi, init_priv); + auto group_info = welcome_obj.decrypt(group_secrets.joiner_secret, {}); + + // Verify signature on GroupInfo + VERIFY("group info verify", group_info.verify(signer_pub)); + + // Verify confirmation tag + const auto& group_context = group_info.group_context; + auto key_schedule = KeyScheduleEpoch::joiner( + cipher_suite, group_secrets.joiner_secret, {}, tls::marshal(group_context)); + auto confirmation_tag = + key_schedule.confirmation_tag(group_context.confirmed_transcript_hash); + + return std::nullopt; +} + +/// +/// TreeTestCase +/// + +std::array all_tree_structures{ + TreeStructure::full_tree_2, + TreeStructure::full_tree_3, + TreeStructure::full_tree_4, + TreeStructure::full_tree_5, + TreeStructure::full_tree_6, + TreeStructure::full_tree_7, + TreeStructure::full_tree_8, + TreeStructure::full_tree_32, + TreeStructure::full_tree_33, + TreeStructure::full_tree_34, + TreeStructure::internal_blanks_no_skipping, + TreeStructure::internal_blanks_with_skipping, + TreeStructure::unmerged_leaves_no_skipping, + TreeStructure::unmerged_leaves_with_skipping, +}; + +std::array treekem_test_tree_structures{ + // All cases except the big ones + TreeStructure::full_tree_2, + TreeStructure::full_tree_3, + TreeStructure::full_tree_4, + TreeStructure::full_tree_5, + TreeStructure::full_tree_6, + TreeStructure::full_tree_7, + TreeStructure::full_tree_8, + TreeStructure::internal_blanks_no_skipping, + TreeStructure::internal_blanks_with_skipping, + TreeStructure::unmerged_leaves_no_skipping, + TreeStructure::unmerged_leaves_with_skipping, +}; + +struct TreeTestCase +{ + CipherSuite suite; + PseudoRandom::Generator prg; + + bytes group_id; + uint32_t leaf_counter = 0; + uint32_t path_counter = 0; + + struct PrivateState + { + SignaturePrivateKey sig_priv; + TreeKEMPrivateKey priv; + std::vector senders; + }; + + std::map privs; + TreeKEMPublicKey pub; + + TreeTestCase(CipherSuite suite_in, PseudoRandom::Generator prg_in) + : suite(suite_in) + , prg(std::move(prg_in)) + , group_id(prg.secret("group_id")) + , pub(suite) + { + auto [where, enc_priv, sig_priv] = add_leaf(); + auto tree_priv = TreeKEMPrivateKey::solo(suite, where, enc_priv); + auto priv_state = PrivateState{ sig_priv, tree_priv, { LeafIndex{ 0 } } }; + privs.insert_or_assign(where, priv_state); + } + + std::tuple add_leaf() + { + leaf_counter += 1; + auto ix = to_hex(tls::marshal(leaf_counter)); + auto enc_priv = prg.hpke_key("encryption_key" + ix); + auto sig_priv = prg.signature_key("signature_key" + ix); + auto identity = prg.secret("identity" + ix); + + auto credential = Credential::basic(identity); + auto leaf_node = LeafNode{ suite, + enc_priv.public_key, + sig_priv.public_key, + credential, + Capabilities::create_default(), + Lifetime::create_default(), + {}, + sig_priv }; + auto where = pub.add_leaf(leaf_node); + pub.set_hash_all(); + return { where, enc_priv, sig_priv }; + } + + void commit(LeafIndex from, + const std::vector& remove, + bool add, + std::optional maybe_context) + { + // Remove members from the tree + for (auto i : remove) { + pub.blank_path(i); + privs.erase(i); + } + pub.set_hash_all(); + + auto joiner = std::vector{}; + auto maybe_enc_priv = std::optional{}; + auto maybe_sig_priv = std::optional{}; + if (add) { + auto [where, enc_priv, sig_priv] = add_leaf(); + joiner.push_back(where); + maybe_enc_priv = enc_priv; + maybe_sig_priv = sig_priv; + } + + auto path_secret = std::optional{}; + if (maybe_context) { + // Create an UpdatePath + path_counter += 1; + auto ix = to_hex(tls::marshal(path_counter)); + auto leaf_secret = prg.secret("leaf_secret" + ix); + auto priv = privs.at(from); + + auto context = opt::get(maybe_context); + auto pub_before = pub; + auto sender_priv = + pub.update(from, leaf_secret, group_id, priv.sig_priv, {}); + auto path = pub.encap(sender_priv, context, joiner); + + // Process the UpdatePath at all the members + for (auto& pair : privs) { + // XXX(RLB): It might seem like this could be done with a simple + // destructuring assignment, either here or in the `for` clause above. + // However, either of these options cause clang-tidy to segfault when + // evaulating the "bugprone-unchecked-optional-access" lint. + const auto& leaf = pair.first; + auto& priv_state = pair.second; + if (leaf == from) { + priv_state = + PrivateState{ priv_state.sig_priv, sender_priv, { from } }; + continue; + } + + priv_state.priv.decap(from, pub_before, context, path, joiner); + priv_state.senders.push_back(from); + } + + // Look up the path secret for the joiner + if (!joiner.empty()) { + auto index = joiner.front(); + auto [overlap, shared_path_secret, ok] = + sender_priv.shared_path_secret(index); + silence_unused(overlap); + silence_unused(ok); + + path_secret = shared_path_secret; + } + } + + // Add a private entry for the joiner if we added someone + if (!joiner.empty()) { + auto index = joiner.front(); + auto ancestor = index.ancestor(from); + auto enc_priv = opt::get(maybe_enc_priv); + auto sig_priv = opt::get(maybe_sig_priv); + auto tree_priv = + TreeKEMPrivateKey::joiner(pub, index, enc_priv, ancestor, path_secret); + privs.insert_or_assign(index, + PrivateState{ sig_priv, tree_priv, { from } }); + } + } + + static TreeTestCase full(CipherSuite suite, + const PseudoRandom::Generator& prg, + LeafCount leaves, + const std::string& label) + { + auto tc = TreeTestCase{ suite, prg.sub(label) }; + + for (LeafIndex i{ 0 }; i.val < leaves.val - 1; i.val++) { + tc.commit( + i, {}, true, tc.prg.secret("context" + to_hex(tls::marshal(i)))); + } + + return tc; + } + + static TreeTestCase with_structure(CipherSuite suite, + const PseudoRandom::Generator& prg, + TreeStructure tree_structure) + { + switch (tree_structure) { + case TreeStructure::full_tree_2: + return full(suite, prg, LeafCount{ 2 }, "full_tree_2"); + + case TreeStructure::full_tree_3: + return full(suite, prg, LeafCount{ 3 }, "full_tree_3"); + + case TreeStructure::full_tree_4: + return full(suite, prg, LeafCount{ 4 }, "full_tree_4"); + + case TreeStructure::full_tree_5: + return full(suite, prg, LeafCount{ 5 }, "full_tree_5"); + + case TreeStructure::full_tree_6: + return full(suite, prg, LeafCount{ 6 }, "full_tree_6"); + + case TreeStructure::full_tree_7: + return full(suite, prg, LeafCount{ 7 }, "full_tree_7"); + + case TreeStructure::full_tree_8: + return full(suite, prg, LeafCount{ 8 }, "full_tree_8"); + + case TreeStructure::full_tree_32: + return full(suite, prg, LeafCount{ 32 }, "full_tree_32"); + + case TreeStructure::full_tree_33: + return full(suite, prg, LeafCount{ 33 }, "full_tree_33"); + + case TreeStructure::full_tree_34: + return full(suite, prg, LeafCount{ 34 }, "full_tree_34"); + + case TreeStructure::internal_blanks_no_skipping: { + auto tc = TreeTestCase::full( + suite, prg, LeafCount{ 8 }, "internal_blanks_no_skipping"); + auto context = tc.prg.secret("context"); + tc.commit( + LeafIndex{ 0 }, { LeafIndex{ 2 }, LeafIndex{ 3 } }, true, context); + return tc; + } + + case TreeStructure::internal_blanks_with_skipping: { + auto tc = TreeTestCase::full( + suite, prg, LeafCount{ 8 }, "internal_blanks_with_skipping"); + auto context = tc.prg.secret("context"); + tc.commit(LeafIndex{ 0 }, + { LeafIndex{ 1 }, LeafIndex{ 2 }, LeafIndex{ 3 } }, + false, + context); + return tc; + } + + case TreeStructure::unmerged_leaves_no_skipping: { + auto tc = TreeTestCase::full( + suite, prg, LeafCount{ 7 }, "unmerged_leaves_no_skipping"); + auto context = tc.prg.secret("context"); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + return tc; + } + + case TreeStructure::unmerged_leaves_with_skipping: { + auto tc = TreeTestCase::full( + suite, prg, LeafCount{ 1 }, "unmerged_leaves_with_skipping"); + + // 0 adds 1..6 + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + + // 0 reemoves 5 + tc.commit(LeafIndex{ 0 }, + { LeafIndex{ 5 } }, + false, + tc.prg.secret("context_remove5")); + + // 4 commits without any proupposals + tc.commit(LeafIndex{ 4 }, {}, false, tc.prg.secret("context_update4")); + + // 0 adds a new member + tc.commit(LeafIndex{ 0 }, {}, true, std::nullopt); + + return tc; + } + + default: + throw InvalidParameterError("Unsupported tree structure"); + } + } +}; + +/// +/// TreeHashTestVector +/// +TreeHashTestVector::TreeHashTestVector(mlspp::CipherSuite suite, + TreeStructure tree_structure) + : PseudoRandom(suite, "tree-hashes") + , cipher_suite(suite) +{ + auto tc = TreeTestCase::with_structure(suite, prg, tree_structure); + tree = tc.pub; + group_id = tc.group_id; + + auto width = NodeCount(tree.size); + for (NodeIndex i{ 0 }; i < width; i.val++) { + tree_hashes.push_back(tree.get_hash(i)); + resolutions.push_back(tree.resolve(i)); + } +} + +std::optional +TreeHashTestVector::verify() +{ + // Finish setting up the tree + tree.suite = cipher_suite; + tree.set_hash_all(); + + // Verify that each leaf node is properly signed + for (LeafIndex i{ 0 }; i < tree.size; i.val++) { + auto maybe_leaf = tree.leaf_node(i); + if (!maybe_leaf) { + continue; + } + + auto leaf = opt::get(maybe_leaf); + auto leaf_valid = leaf.verify(cipher_suite, { { group_id, i } }); + VERIFY("leaf sig valid", leaf_valid); + } + + // Verify the tree hashes + auto width = NodeCount{ tree.size }; + for (NodeIndex i{ 0 }; i < width; i.val++) { + VERIFY_EQUAL("tree hash", tree.get_hash(i), tree_hashes.at(i.val)); + VERIFY_EQUAL("resolution", tree.resolve(i), resolutions.at(i.val)); + } + + // Verify parent hashes + VERIFY("parent hash valid", tree.parent_hash_valid()); + + // Verify the resolutions + for (NodeIndex i{ 0 }; i < width; i.val++) { + VERIFY_EQUAL("resolution", tree.resolve(i), resolutions[i.val]); + } + + return std::nullopt; +} + +/// +/// TreeOperationsTestVector +/// + +const std::vector + TreeOperationsTestVector::all_scenarios{ + Scenario::add_right_edge, Scenario::add_internal, Scenario::update, + Scenario::remove_right_edge, Scenario::remove_internal, + }; + +TreeOperationsTestVector::TreeOperationsTestVector( + mlspp::CipherSuite suite, + Scenario scenario) + : PseudoRandom(suite, "tree-operations") + , cipher_suite(suite) + , proposal_sender(0) +{ + auto init_priv = prg.hpke_key("init_key"); + auto enc_priv = prg.hpke_key("encryption_key"); + auto sig_priv = prg.signature_key("signature_key"); + auto identity = prg.secret("identity"); + auto credential = Credential::basic(identity); + auto key_package = KeyPackage{ + suite, + init_priv.public_key, + { suite, + enc_priv.public_key, + sig_priv.public_key, + credential, + Capabilities::create_default(), + Lifetime::create_default(), + {}, + sig_priv }, + {}, + sig_priv, + }; + + switch (scenario) { + case Scenario::add_right_edge: { + auto tc = TreeTestCase::full(suite, prg, LeafCount{ 8 }, "tc"); + + proposal = Proposal{ Add{ key_package } }; + + tree_before = tc.pub; + tree_hash_before = tree_before.root_hash(); + + tree_after = tree_before; + tree_after.add_leaf(key_package.leaf_node); + break; + } + + case Scenario::add_internal: { + auto tc = TreeTestCase::full(suite, prg, LeafCount{ 8 }, "tc"); + + proposal = Proposal{ Add{ key_package } }; + + tree_before = tc.pub; + tree_before.blank_path(LeafIndex{ 4 }); + tree_before.set_hash_all(); + tree_hash_before = tree_before.root_hash(); + + tree_after = tree_before; + tree_after.add_leaf(key_package.leaf_node); + break; + } + + case Scenario::update: { + auto tc = TreeTestCase::full(suite, prg, LeafCount{ 8 }, "tc"); + + proposal_sender = LeafIndex{ 3 }; + proposal = Proposal{ Update{ key_package.leaf_node } }; + + tree_before = tc.pub; + tree_hash_before = tree_before.root_hash(); + + tree_after = tree_before; + tree_after.update_leaf(proposal_sender, key_package.leaf_node); + break; + } + + case Scenario::remove_right_edge: { + auto tc = TreeTestCase::full(suite, prg, LeafCount{ 9 }, "tc"); + + auto removed = LeafIndex{ 8 }; + proposal = Proposal{ Remove{ removed } }; + + tree_before = tc.pub; + tree_hash_before = tree_before.root_hash(); + + tree_after = tree_before; + tree_after.blank_path(removed); + tree_after.truncate(); + break; + } + + case Scenario::remove_internal: { + auto tc = TreeTestCase::full(suite, prg, LeafCount{ 8 }, "tc"); + + auto removed = LeafIndex{ 4 }; + proposal = Proposal{ Remove{ removed } }; + + tree_before = tc.pub; + tree_hash_before = tree_before.root_hash(); + + tree_after = tree_before; + tree_after.blank_path(removed); + tree_after.truncate(); + break; + } + } + + tree_after.set_hash_all(); + tree_hash_after = tree_after.root_hash(); +} + +std::optional +TreeOperationsTestVector::verify() +{ + tree_before.suite = cipher_suite; + tree_before.set_hash_all(); + + auto tree = tree_before; + VERIFY_EQUAL("tree hash before", tree.root_hash(), tree_hash_before); + + auto apply = overloaded{ + [&](const Add& add) { tree.add_leaf(add.key_package.leaf_node); }, + + [&](const Update& update) { + tree.update_leaf(proposal_sender, update.leaf_node); + }, + + [&](const Remove& remove) { + tree.blank_path(remove.removed); + tree.truncate(); + }, + + [](const auto& /* other */) { + throw InvalidParameterError("invalid proposal type"); + }, + }; + + var::visit(apply, proposal.content); + VERIFY_EQUAL("tree after", tree, tree_after); + + tree.set_hash_all(); + VERIFY_EQUAL("tree hash after", tree.root_hash(), tree_hash_after); + + return std::nullopt; +} + +/// +/// TreeKEMTestVector +/// + +TreeKEMTestVector::TreeKEMTestVector(mlspp::CipherSuite suite, + TreeStructure tree_structure) + : PseudoRandom(suite, "treekem") + , cipher_suite(suite) +{ + auto tc = TreeTestCase::with_structure(cipher_suite, prg, tree_structure); + + group_id = tc.group_id; + epoch = prg.uint64("epoch"); + confirmed_transcript_hash = prg.secret("confirmed_transcript_hash"); + + ratchet_tree = tc.pub; + + // Serialize out the private states + for (LeafIndex index{ 0 }; index < ratchet_tree.size; index.val++) { + if (tc.privs.count(index) == 0) { + continue; + } + + auto priv_state = tc.privs.at(index); + auto enc_priv = priv_state.priv.private_key_cache.at(NodeIndex(index)); + auto path_secrets = std::vector{}; + for (const auto& [node, path_secret] : priv_state.priv.path_secrets) { + if (node == NodeIndex(index)) { + // No need to serialize a secret for the leaf node + continue; + } + + path_secrets.push_back(PathSecret{ node, path_secret }); + } + + leaves_private.push_back(LeafPrivateInfo{ + index, + enc_priv, + priv_state.sig_priv, + path_secrets, + }); + } + + // Create test update paths + for (LeafIndex sender{ 0 }; sender < ratchet_tree.size; sender.val++) { + if (!tc.pub.has_leaf(sender)) { + continue; + } + + auto leaf_secret = prg.secret("update_path" + to_hex(tls::marshal(sender))); + const auto& sig_priv = tc.privs.at(sender).sig_priv; + + auto pub = tc.pub; + auto new_sender_priv = + pub.update(sender, leaf_secret, group_id, sig_priv, {}); + + auto group_context = GroupContext{ cipher_suite, + group_id, + epoch, + pub.root_hash(), + confirmed_transcript_hash, + {} }; + auto ctx = tls::marshal(group_context); + + auto path = pub.encap(new_sender_priv, ctx, {}); + + auto path_secrets = std::vector>{}; + for (LeafIndex to{ 0 }; to < ratchet_tree.size; to.val++) { + if (to == sender || !pub.has_leaf(to)) { + path_secrets.emplace_back(std::nullopt); + continue; + } + + auto [overlap, path_secret, ok] = new_sender_priv.shared_path_secret(to); + silence_unused(overlap); + silence_unused(ok); + + path_secrets.emplace_back(path_secret); + } + + update_paths.push_back(UpdatePathInfo{ + sender, + path, + path_secrets, + new_sender_priv.update_secret, + pub.root_hash(), + }); + } +} + +std::optional +TreeKEMTestVector::verify() +{ + // Finish initializing the ratchet tree + ratchet_tree.suite = cipher_suite; + ratchet_tree.set_hash_all(); + + // Validate public state + VERIFY("parent hash valid", ratchet_tree.parent_hash_valid()); + + for (LeafIndex i{ 0 }; i < ratchet_tree.size; i.val++) { + auto maybe_leaf = ratchet_tree.leaf_node(i); + if (!maybe_leaf) { + continue; + } + + auto leaf = opt::get(maybe_leaf); + VERIFY("leaf sig", leaf.verify(cipher_suite, { { group_id, i } })); + } + + // Import private keys + std::map tree_privs; + std::map sig_privs; + for (const auto& info : leaves_private) { + auto enc_priv = info.encryption_priv; + auto sig_priv = info.signature_priv; + enc_priv.set_public_key(cipher_suite); + sig_priv.set_public_key(cipher_suite); + + auto priv = TreeKEMPrivateKey{}; + priv.suite = cipher_suite; + priv.index = info.index; + priv.private_key_cache.insert_or_assign(NodeIndex(info.index), enc_priv); + + for (const auto& entry : info.path_secrets) { + priv.path_secrets.insert_or_assign(entry.node, entry.path_secret); + } + + VERIFY("priv consistent", priv.consistent(ratchet_tree)); + + tree_privs.insert_or_assign(info.index, priv); + sig_privs.insert_or_assign(info.index, sig_priv); + } + + for (const auto& info : update_paths) { + // Test decap of the existing group secrets + const auto& from = info.sender; + const auto& path = info.update_path; + VERIFY("path parent hash valid", + ratchet_tree.parent_hash_valid(from, path)); + + auto ratchet_tree_after = ratchet_tree; + ratchet_tree_after.merge(from, path); + ratchet_tree_after.set_hash_all(); + VERIFY_EQUAL( + "tree hash after", ratchet_tree_after.root_hash(), info.tree_hash_after); + + auto group_context = GroupContext{ cipher_suite, + group_id, + epoch, + ratchet_tree_after.root_hash(), + confirmed_transcript_hash, + {} }; + auto ctx = tls::marshal(group_context); + + for (LeafIndex to{ 0 }; to < ratchet_tree_after.size; to.val++) { + if (to == from || !ratchet_tree_after.has_leaf(to)) { + continue; + } + + auto priv = tree_privs.at(to); + priv.decap(from, ratchet_tree_after, ctx, path, {}); + VERIFY_EQUAL("commit secret", priv.update_secret, info.commit_secret); + + auto [overlap, path_secret, ok] = priv.shared_path_secret(from); + silence_unused(overlap); + silence_unused(ok); + VERIFY_EQUAL("path secret", path_secret, info.path_secrets[to.val]); + } + + // Test encap/decap + auto ratchet_tree_encap = ratchet_tree; + auto leaf_secret = random_bytes(cipher_suite.secret_size()); + const auto& sig_priv = sig_privs.at(from); + auto new_sender_priv = + ratchet_tree_encap.update(from, leaf_secret, group_id, sig_priv, {}); + auto new_path = ratchet_tree_encap.encap(new_sender_priv, ctx, {}); + VERIFY("new path parent hash valid", + ratchet_tree.parent_hash_valid(from, path)); + + for (LeafIndex to{ 0 }; to < ratchet_tree_encap.size; to.val++) { + if (to == from || !ratchet_tree_encap.has_leaf(to)) { + continue; + } + + auto priv = tree_privs.at(to); + priv.decap(from, ratchet_tree_encap, ctx, new_path, {}); + VERIFY_EQUAL( + "commit secret", priv.update_secret, new_sender_priv.update_secret); + } + } + + return std::nullopt; +} + +/// +/// MessagesTestVector +/// + +MessagesTestVector::MessagesTestVector() + : PseudoRandom(CipherSuite::ID::X25519_AES128GCM_SHA256_Ed25519, "messages") +{ + auto suite = CipherSuite{ CipherSuite::ID::X25519_AES128GCM_SHA256_Ed25519 }; + auto epoch = epoch_t(prg.uint64("epoch")); + auto index = LeafIndex{ prg.uint32("index") }; + auto user_id = prg.secret("user_id"); + auto group_id = prg.secret("group_id"); + // auto opaque = bytes(32, 0xD3); + // auto mac = bytes(32, 0xD5); + + auto app_id_ext = ApplicationIDExtension{ prg.secret("app_id") }; + auto ext_list = ExtensionList{}; + ext_list.add(app_id_ext); + + auto group_context = GroupContext{ suite, + group_id, + epoch, + prg.secret("tree_hash"), + prg.secret("confirmed_trasncript_hash"), + ext_list }; + + auto version = ProtocolVersion::mls10; + auto hpke_priv = prg.hpke_key("hpke_priv"); + auto hpke_priv_2 = prg.hpke_key("hpke_priv_2"); + auto hpke_pub = hpke_priv.public_key; + auto hpke_pub_2 = hpke_priv_2.public_key; + auto hpke_ct = + HPKECiphertext{ prg.secret("kem_output"), prg.secret("ciphertext") }; + auto sig_priv = prg.signature_key("signature_priv"); + auto sig_priv_2 = prg.signature_key("signature_priv_2"); + auto sig_pub = sig_priv.public_key; + auto sig_pub_2 = sig_priv_2.public_key; + + // KeyPackage and extensions + auto cred = Credential::basic(user_id); + auto leaf_node = LeafNode{ suite, + hpke_pub, + sig_pub, + cred, + Capabilities::create_default(), + Lifetime::create_default(), + ext_list, + sig_priv }; + auto leaf_node_2 = LeafNode{ suite, + hpke_pub_2, + sig_pub_2, + cred, + Capabilities::create_default(), + Lifetime::create_default(), + ext_list, + sig_priv_2 }; + auto key_package_obj = KeyPackage{ suite, hpke_pub, leaf_node, {}, sig_priv }; + + auto leaf_node_update = + leaf_node.for_update(suite, group_id, index, hpke_pub, {}, sig_priv); + auto leaf_node_commit = leaf_node.for_commit( + suite, group_id, index, hpke_pub, prg.secret("parent_hash"), {}, sig_priv); + + auto sender = Sender{ MemberSender{ index } }; + + auto tree = TreeKEMPublicKey{ suite }; + tree.add_leaf(leaf_node); + tree.add_leaf(leaf_node_2); + auto ratchet_tree_obj = RatchetTreeExtension{ tree }; + + // Welcome and its substituents + auto group_info_obj = + GroupInfo{ group_context, ext_list, prg.secret("confirmation_tag") }; + auto joiner_secret = prg.secret("joiner_secret"); + auto path_secret = prg.secret("path_secret"); + auto psk_id = ExternalPSK{ prg.secret("psk_id") }; + auto psk_nonce = prg.secret("psk_nonce"); + auto group_secrets_obj = GroupSecrets{ joiner_secret, + { { path_secret } }, + PreSharedKeys{ { + { psk_id, psk_nonce }, + } } }; + auto welcome_obj = Welcome{ suite, joiner_secret, {}, group_info_obj }; + welcome_obj.encrypt(key_package_obj, path_secret); + + // Proposals + auto add = Add{ key_package_obj }; + auto update = Update{ leaf_node_update }; + auto remove = Remove{ index }; + auto pre_shared_key = PreSharedKey{ psk_id, psk_nonce }; + auto reinit = ReInit{ group_id, version, suite, {} }; + auto external_init = ExternalInit{ prg.secret("external_init") }; + + // Commit + auto proposal_ref = ProposalRef{ 32, 0xa0 }; + + auto commit_obj = Commit{ { + { proposal_ref }, + { Proposal{ add } }, + }, + UpdatePath{ + leaf_node_commit, + { + { hpke_pub, { hpke_ct, hpke_ct } }, + { hpke_pub, { hpke_ct, hpke_ct, hpke_ct } }, + }, + } }; + + // AuthenticatedContent with Application / Proposal / Commit + + // PublicMessage + auto membership_key = prg.secret("membership_key"); + + auto content_auth_proposal = AuthenticatedContent::sign( + WireFormat::mls_public_message, + { group_id, epoch, sender, {}, Proposal{ remove } }, + suite, + sig_priv, + group_context); + auto public_message_proposal_obj = PublicMessage::protect( + content_auth_proposal, suite, membership_key, group_context); + + auto content_auth_commit = + AuthenticatedContent::sign(WireFormat::mls_public_message, + { group_id, epoch, sender, {}, commit_obj }, + suite, + sig_priv, + group_context); + content_auth_commit.set_confirmation_tag(prg.secret("confirmation_tag")); + auto public_message_commit_obj = PublicMessage::protect( + content_auth_commit, suite, membership_key, group_context); + + // PrivateMessage + auto content_auth_application_obj = AuthenticatedContent::sign( + WireFormat::mls_private_message, + { group_id, epoch, sender, {}, ApplicationData{} }, + suite, + sig_priv, + group_context); + + auto keys = GroupKeySource( + suite, LeafCount{ index.val + 1 }, prg.secret("encryption_secret")); + auto private_message_obj = + PrivateMessage::protect(content_auth_application_obj, + suite, + keys, + prg.secret("sender_data_secret"), + 10); + + // Serialize out all the objects + mls_welcome = tls::marshal(MLSMessage{ welcome_obj }); + mls_group_info = tls::marshal(MLSMessage{ group_info_obj }); + mls_key_package = tls::marshal(MLSMessage{ key_package_obj }); + + ratchet_tree = tls::marshal(ratchet_tree_obj); + group_secrets = tls::marshal(group_secrets_obj); + + add_proposal = tls::marshal(add); + update_proposal = tls::marshal(update); + remove_proposal = tls::marshal(remove); + pre_shared_key_proposal = tls::marshal(pre_shared_key); + re_init_proposal = tls::marshal(reinit); + external_init_proposal = tls::marshal(external_init); + + commit = tls::marshal(commit_obj); + + public_message_proposal = + tls::marshal(MLSMessage{ public_message_proposal_obj }); + public_message_commit = tls::marshal(MLSMessage{ public_message_commit_obj }); + private_message = tls::marshal(MLSMessage{ private_message_obj }); +} + +std::optional +MessagesTestVector::verify() const +{ + // TODO(RLB) Verify signatures + // TODO(RLB) Verify content types in PublicMessage objects + auto require_format = [](WireFormat format) { + return + [format](const MLSMessage& msg) { return msg.wire_format() == format; }; + }; + + VERIFY_TLS_RTT_VAL("Welcome", + MLSMessage, + mls_welcome, + require_format(WireFormat::mls_welcome)); + VERIFY_TLS_RTT_VAL("GroupInfo", + MLSMessage, + mls_group_info, + require_format(WireFormat::mls_group_info)); + VERIFY_TLS_RTT_VAL("KeyPackage", + MLSMessage, + mls_key_package, + require_format(WireFormat::mls_key_package)); + + VERIFY_TLS_RTT("RatchetTree", RatchetTreeExtension, ratchet_tree); + VERIFY_TLS_RTT("GroupSecrets", GroupSecrets, group_secrets); + + VERIFY_TLS_RTT("Add", Add, add_proposal); + VERIFY_TLS_RTT("Update", Update, update_proposal); + VERIFY_TLS_RTT("Remove", Remove, remove_proposal); + VERIFY_TLS_RTT("PreSharedKey", PreSharedKey, pre_shared_key_proposal); + VERIFY_TLS_RTT("ReInit", ReInit, re_init_proposal); + VERIFY_TLS_RTT("ExternalInit", ExternalInit, external_init_proposal); + + VERIFY_TLS_RTT("Commit", Commit, commit); + + VERIFY_TLS_RTT_VAL("Public(Proposal)", + MLSMessage, + public_message_proposal, + require_format(WireFormat::mls_public_message)); + VERIFY_TLS_RTT_VAL("Public(Commit)", + MLSMessage, + public_message_commit, + require_format(WireFormat::mls_public_message)); + VERIFY_TLS_RTT_VAL("PrivateMessage", + MLSMessage, + private_message, + require_format(WireFormat::mls_private_message)); + + return std::nullopt; +} + +std::optional +PassiveClientTestVector::verify() +{ + // Import everything + signature_priv.set_public_key(cipher_suite); + encryption_priv.set_public_key(cipher_suite); + init_priv.set_public_key(cipher_suite); + + const auto& key_package_raw = var::get(key_package.message); + const auto& welcome_raw = var::get(welcome.message); + + auto ext_psks = std::map{}; + for (const auto& [id, psk] : external_psks) { + ext_psks.insert_or_assign(id, psk); + } + + // Join the group and follow along + auto state = State(init_priv, + encryption_priv, + signature_priv, + key_package_raw, + welcome_raw, + ratchet_tree, + ext_psks); + VERIFY_EQUAL( + "initial epoch", state.epoch_authenticator(), initial_epoch_authenticator); + + for (const auto& tve : epochs) { + for (const auto& proposal : tve.proposals) { + state.handle(proposal); + } + + state = opt::get(state.handle(tve.commit)); + VERIFY_EQUAL( + "epoch auth", state.epoch_authenticator(), tve.epoch_authenticator) + } + + return std::nullopt; +} + +} // namespace mls_vectors diff --git a/mlspp/lib/tls_syntax/CMakeLists.txt b/mlspp/lib/tls_syntax/CMakeLists.txt new file mode 100755 index 0000000000..40d4f93619 --- /dev/null +++ b/mlspp/lib/tls_syntax/CMakeLists.txt @@ -0,0 +1,21 @@ +set(CURRENT_LIB_NAME tls_syntax) + +### +### Library Config +### + +file(GLOB_RECURSE LIB_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE LIB_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") + +add_library(${CURRENT_LIB_NAME} STATIC ${LIB_HEADERS} ${LIB_SOURCES}) +target_include_directories(${CURRENT_LIB_NAME} + PUBLIC + $ + $ + $ +) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/bytes/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/hpke/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/mls_vectors/include") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../lib/tls_syntax/include") diff --git a/mlspp/lib/tls_syntax/include/tls/compat.h b/mlspp/lib/tls_syntax/include/tls/compat.h new file mode 100755 index 0000000000..095cc17ff6 --- /dev/null +++ b/mlspp/lib/tls_syntax/include/tls/compat.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#ifdef VARIANT_COMPAT +#include +#else +#include +#endif // VARIANT_COMPAT + +namespace mlspp::tls { + +namespace var = std; + +// In a similar vein, we provide our own safe accessors for std::optional, since +// std::optional::value() is not available on macOS 10.11. +namespace opt { + +template +T& +get(std::optional& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return *opt; +} + +template +const T& +get(const std::optional& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return *opt; +} + +template +T&& +get(std::optional&& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return std::move(*opt); +} + +template +const T&& +get(const std::optional&& opt) +{ + if (!opt) { + throw std::runtime_error("bad_optional_access"); + } + return std::move(*opt); +} + +} // namespace opt +} // namespace mlspp::tls diff --git a/mlspp/lib/tls_syntax/include/tls/tls_syntax.h b/mlspp/lib/tls_syntax/include/tls/tls_syntax.h new file mode 100755 index 0000000000..09d5940d9d --- /dev/null +++ b/mlspp/lib/tls_syntax/include/tls/tls_syntax.h @@ -0,0 +1,569 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mlspp::tls { + +// For indicating no min or max in vector definitions +const size_t none = std::numeric_limits::max(); + +class WriteError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +class ReadError : public std::invalid_argument +{ +public: + using parent = std::invalid_argument; + using parent::parent; +}; + +/// +/// Declarations of Streams and Traits +/// + +class ostream +{ +public: + static const size_t none = std::numeric_limits::max(); + + void write_raw(const std::vector& bytes); + + const std::vector& bytes() const { return _buffer; } + size_t size() const { return _buffer.size(); } + bool empty() const { return _buffer.empty(); } + +private: + std::vector _buffer; + ostream& write_uint(uint64_t value, int length); + + friend ostream& operator<<(ostream& out, bool data); + friend ostream& operator<<(ostream& out, uint8_t data); + friend ostream& operator<<(ostream& out, uint16_t data); + friend ostream& operator<<(ostream& out, uint32_t data); + friend ostream& operator<<(ostream& out, uint64_t data); + + template + friend ostream& operator<<(ostream& out, const std::vector& data); + + friend struct varint; +}; + +class istream +{ +public: + istream(const std::vector& data) + : _buffer(data) + { + // So that we can use the constant-time pop_back + std::reverse(_buffer.begin(), _buffer.end()); + } + + size_t size() const { return _buffer.size(); } + bool empty() const { return _buffer.empty(); } + + std::vector bytes() + { + auto bytes = _buffer; + std::reverse(bytes.begin(), bytes.end()); + return bytes; + } + +private: + istream() {} + std::vector _buffer; + uint8_t next(); + + template + istream& read_uint(T& data, size_t length) + { + uint64_t value = 0; + for (size_t i = 0; i < length; i += 1) { + value = (value << unsigned(8)) + next(); + } + data = static_cast(value); + return *this; + } + + friend istream& operator>>(istream& in, bool& data); + friend istream& operator>>(istream& in, uint8_t& data); + friend istream& operator>>(istream& in, uint16_t& data); + friend istream& operator>>(istream& in, uint32_t& data); + friend istream& operator>>(istream& in, uint64_t& data); + + template + friend istream& operator>>(istream& in, std::vector& data); + + friend struct varint; +}; + +// Traits must have static encode and decode methods, of the following form: +// +// static ostream& encode(ostream& str, const T& val); +// static istream& decode(istream& str, T& val); +// +// Trait types will never be constructed; only these static methods are used. +// The value arguments to encode and decode can be as strict or as loose as +// desired. +// +// Ultimately, all interesting encoding should be done through traits. +// +// * vectors +// * variants +// * varints + +struct pass +{ + template + static ostream& encode(ostream& str, const T& val); + + template + static istream& decode(istream& str, T& val); +}; + +template +struct variant +{ + template + static inline Ts type(const var::variant& data); + + template + static ostream& encode(ostream& str, const var::variant& data); + + template + static inline typename std::enable_if::type + read_variant(istream&, Te, var::variant&); + + template + static inline typename std::enable_if < + I::type read_variant(istream& str, + Te target_type, + var::variant& v); + + template + static istream& decode(istream& str, var::variant& data); +}; + +struct varint +{ + static ostream& encode(ostream& str, const uint64_t& val); + static istream& decode(istream& str, uint64_t& val); +}; + +/// +/// Writer implementations +/// + +// Primitive writers defined in .cpp file + +// Array writer +template +ostream& +operator<<(ostream& out, const std::array& data) +{ + for (const auto& item : data) { + out << item; + } + return out; +} + +// Optional writer +template +ostream& +operator<<(ostream& out, const std::optional& opt) +{ + if (!opt) { + return out << uint8_t(0); + } + + return out << uint8_t(1) << opt::get(opt); +} + +// Enum writer +template::value, int> = 0> +ostream& +operator<<(ostream& str, const T& val) +{ + auto u = static_cast>(val); + return str << u; +} + +// Vector writer +template +ostream& +operator<<(ostream& str, const std::vector& vec) +{ + // Pre-encode contents + ostream temp; + for (const auto& item : vec) { + temp << item; + } + + // Write the encoded length, then the pre-encoded data + varint::encode(str, temp._buffer.size()); + str.write_raw(temp.bytes()); + + return str; +} + +/// +/// Reader implementations +/// + +// Primitive type readers defined in .cpp file + +// Array reader +template +istream& +operator>>(istream& in, std::array& data) +{ + for (auto& item : data) { + in >> item; + } + return in; +} + +// Optional reader +template +istream& +operator>>(istream& in, std::optional& opt) +{ + uint8_t present = 0; + in >> present; + + switch (present) { + case 0: + opt.reset(); + return in; + + case 1: + opt.emplace(); + return in >> opt::get(opt); + + default: + throw std::invalid_argument("Malformed optional"); + } +} + +// Enum reader +// XXX(rlb): It would be nice if this could enforce that the values are valid, +// but C++ doesn't seem to have that ability. When used as a tag for variants, +// the variant reader will enforce, at least. +template::value, int> = 0> +istream& +operator>>(istream& str, T& val) +{ + std::underlying_type_t u; + str >> u; + val = static_cast(u); + return str; +} + +// Vector reader +template +istream& +operator>>(istream& str, std::vector& vec) +{ + // Read the encoded data size + auto size = uint64_t(0); + varint::decode(str, size); + if (size > str._buffer.size()) { + throw ReadError("Vector is longer than remaining data"); + } + + // Read the elements of the vector + // NB: Remember that we store the vector in reverse order + // NB: This requires that T be default-constructible + istream r; + r._buffer = + std::vector{ str._buffer.end() - size, str._buffer.end() }; + + vec.clear(); + while (r._buffer.size() > 0) { + vec.emplace_back(); + r >> vec.back(); + } + + // Truncate the primary buffer + str._buffer.erase(str._buffer.end() - size, str._buffer.end()); + + return str; +} + +// Abbreviations +template +std::vector +marshal(const T& value) +{ + ostream w; + w << value; + return w.bytes(); +} + +template +void +unmarshal(const std::vector& data, T& value) +{ + istream r(data); + r >> value; +} + +template +T +get(const std::vector& data, Tp... args) +{ + T value(args...); + unmarshal(data, value); + return value; +} + +// Use this macro to define struct serialization with minimal boilerplate +#define TLS_SERIALIZABLE(...) \ + static const bool _tls_serializable = true; \ + auto _tls_fields_r() \ + { \ + return std::forward_as_tuple(__VA_ARGS__); \ + } \ + auto _tls_fields_w() const \ + { \ + return std::forward_as_tuple(__VA_ARGS__); \ + } + +// If your struct contains nontrivial members (e.g., vectors), use this to +// define traits for them. +#define TLS_TRAITS(...) \ + static const bool _tls_has_traits = true; \ + using _tls_traits = std::tuple<__VA_ARGS__>; + +template +struct is_serializable +{ + template + static std::true_type test(decltype(U::_tls_serializable)); + + template + static std::false_type test(...); + + static const bool value = decltype(test(true))::value; +}; + +template +struct has_traits +{ + template + static std::true_type test(decltype(U::_tls_has_traits)); + + template + static std::false_type test(...); + + static const bool value = decltype(test(true))::value; +}; + +/// +/// Trait implementations +/// + +// Pass-through (normal encoding/decoding) +template +ostream& +pass::encode(ostream& str, const T& val) +{ + return str << val; +} + +template +istream& +pass::decode(istream& str, T& val) +{ + return str >> val; +} + +// Variant encoding +template +constexpr Ts +variant_map(); + +#define TLS_VARIANT_MAP(EnumType, MappedType, enum_value) \ + template<> \ + constexpr EnumType variant_map() \ + { \ + return EnumType::enum_value; \ + } + +template +template +inline Ts +variant::type(const var::variant& data) +{ + const auto get_type = [](const auto& v) { + return variant_map>(); + }; + return var::visit(get_type, data); +} + +template +template +ostream& +variant::encode(ostream& str, const var::variant& data) +{ + const auto write_variant = [&str](auto&& v) { + using Tv = std::decay_t; + str << variant_map() << v; + }; + var::visit(write_variant, data); + return str; +} + +template +template +inline typename std::enable_if::type +variant::read_variant(istream&, Te, var::variant&) +{ + throw ReadError("Invalid variant type label"); +} + +template + template + inline + typename std::enable_if < I::type + variant::read_variant(istream& str, + Te target_type, + var::variant& v) +{ + using Tc = var::variant_alternative_t>; + if (variant_map() == target_type) { + str >> v.template emplace(); + return; + } + + read_variant(str, target_type, v); +} + +template +template +istream& +variant::decode(istream& str, var::variant& data) +{ + Ts target_type; + str >> target_type; + read_variant(str, target_type, data); + return str; +} + +// Struct writer without traits (enabled by macro) +template +inline typename std::enable_if::type +write_tuple(ostream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + write_tuple(ostream& str, const std::tuple& t) +{ + str << std::get(t); + write_tuple(str, t); +} + +template +inline + typename std::enable_if::value && !has_traits::value, + ostream&>::type + operator<<(ostream& str, const T& obj) +{ + write_tuple(str, obj._tls_fields_w()); + return str; +} + +// Struct writer with traits (enabled by macro) +template +inline typename std::enable_if::type +write_tuple_traits(ostream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + write_tuple_traits(ostream& str, const std::tuple& t) +{ + std::tuple_element_t::encode(str, std::get(t)); + write_tuple_traits(str, t); +} + +template +inline + typename std::enable_if::value && has_traits::value, + ostream&>::type + operator<<(ostream& str, const T& obj) +{ + write_tuple_traits(str, obj._tls_fields_w()); + return str; +} + +// Struct reader without traits (enabled by macro) +template +inline typename std::enable_if::type +read_tuple(istream&, const std::tuple&) +{ +} + +template + inline + typename std::enable_if < I::type + read_tuple(istream& str, const std::tuple& t) +{ + str >> std::get(t); + read_tuple(str, t); +} + +template +inline + typename std::enable_if::value && !has_traits::value, + istream&>::type + operator>>(istream& str, T& obj) +{ + read_tuple(str, obj._tls_fields_r()); + return str; +} + +// Struct reader with traits (enabled by macro) +template +inline typename std::enable_if::type +read_tuple_traits(istream&, const std::tuple&) +{ +} + +template + inline typename std::enable_if < + I::type + read_tuple_traits(istream& str, const std::tuple& t) +{ + std::tuple_element_t::decode(str, std::get(t)); + read_tuple_traits(str, t); +} + +template +inline + typename std::enable_if::value && has_traits::value, + istream&>::type + operator>>(istream& str, T& obj) +{ + read_tuple_traits(str, obj._tls_fields_r()); + return str; +} + +} // namespace mlspp::tls diff --git a/mlspp/lib/tls_syntax/src/tls_syntax.cpp b/mlspp/lib/tls_syntax/src/tls_syntax.cpp new file mode 100755 index 0000000000..efbea150b5 --- /dev/null +++ b/mlspp/lib/tls_syntax/src/tls_syntax.cpp @@ -0,0 +1,178 @@ +#include + +// NOLINTNEXTLINE(llvmlibc-implementation-in-namespace) +namespace mlspp::tls { + +void +ostream::write_raw(const std::vector& bytes) +{ + // Not sure what the default argument is here + _buffer.insert(_buffer.end(), bytes.begin(), bytes.end()); +} + +// Primitive type writers +ostream& +ostream::write_uint(uint64_t value, int length) +{ + for (int i = length - 1; i >= 0; --i) { + _buffer.push_back(static_cast(value >> unsigned(8 * i))); + } + return *this; +} + +ostream& +operator<<(ostream& out, bool data) +{ + if (data) { + return out << uint8_t(1); + } + + return out << uint8_t(0); +} + +ostream& +operator<<(ostream& out, uint8_t data) // NOLINT(llvmlibc-callee-namespace) +{ + return out.write_uint(data, 1); +} + +ostream& +operator<<(ostream& out, uint16_t data) +{ + return out.write_uint(data, 2); +} + +ostream& +operator<<(ostream& out, uint32_t data) +{ + return out.write_uint(data, 4); +} + +ostream& +operator<<(ostream& out, uint64_t data) +{ + return out.write_uint(data, 8); +} + +// Because pop_back() on an empty vector is undefined +uint8_t +istream::next() +{ + if (_buffer.empty()) { + throw ReadError("Attempt to read from empty buffer"); + } + + const uint8_t value = _buffer.back(); + _buffer.pop_back(); + return value; +} + +// Primitive type readers + +istream& +operator>>(istream& in, bool& data) +{ + uint8_t val = 0; + in >> val; + + // Linter thinks uint8_t is signed (?) + // NOLINTNEXTLINE(hicpp-signed-bitwise) + if ((val & 0xFE) != 0) { + throw ReadError("Malformed boolean"); + } + + data = (val == 1); + return in; +} + +istream& +operator>>(istream& in, uint8_t& data) // NOLINT(llvmlibc-callee-namespace) +{ + return in.read_uint(data, 1); +} + +istream& +operator>>(istream& in, uint16_t& data) +{ + return in.read_uint(data, 2); +} + +istream& +operator>>(istream& in, uint32_t& data) +{ + return in.read_uint(data, 4); +} + +istream& +operator>>(istream& in, uint64_t& data) +{ + return in.read_uint(data, 8); +} + +// Varint encoding +static constexpr size_t VARINT_HEADER_OFFSET = 6; +static constexpr uint64_t VARINT_1_HEADER = 0x00; // 0 << V1_OFFSET +static constexpr uint64_t VARINT_2_HEADER = 0x4000; // 1 << V2_OFFSET +static constexpr uint64_t VARINT_4_HEADER = 0x80000000; // 2 << V4_OFFSET +static constexpr uint64_t VARINT_1_MAX = 0x3f; +static constexpr uint64_t VARINT_2_MAX = 0x3fff; +static constexpr uint64_t VARINT_4_MAX = 0x3fffffff; + +ostream& +varint::encode(ostream& str, const uint64_t& val) +{ + if (val <= VARINT_1_MAX) { + return str.write_uint(VARINT_1_HEADER | val, 1); + } + + if (val <= VARINT_2_MAX) { + return str.write_uint(VARINT_2_HEADER | val, 2); + } + + if (val <= VARINT_4_MAX) { + return str.write_uint(VARINT_4_HEADER | val, 4); + } + + throw WriteError("Varint value exceeds maximum size"); +} + +istream& +varint::decode(istream& str, uint64_t& val) +{ + auto log_size = size_t(str._buffer.back() >> VARINT_HEADER_OFFSET); + if (log_size > 2) { + throw ReadError("Malformed varint header"); + } + + auto read = uint64_t(0); + auto read_bytes = size_t(size_t(1) << log_size); + str.read_uint(read, read_bytes); + + switch (log_size) { + case 0: + read ^= VARINT_1_HEADER; + break; + + case 1: + read ^= VARINT_2_HEADER; + if (read <= VARINT_1_MAX) { + throw ReadError("Non-minimal varint"); + } + break; + + case 2: + read ^= VARINT_4_HEADER; + if (read <= VARINT_2_MAX) { + throw ReadError("Non-minimal varint"); + } + break; + + default: + throw ReadError("Malformed varint header"); + } + + val = read; + return str; +} + +} // namespace mlspp::tls diff --git a/mlspp/src/common.cpp b/mlspp/src/common.cpp new file mode 100755 index 0000000000..6895bfb4d7 --- /dev/null +++ b/mlspp/src/common.cpp @@ -0,0 +1,13 @@ +#include "mls/common.h" + +namespace mlspp { + +uint64_t +seconds_since_epoch() +{ + // TODO(RLB) This should use std::chrono, but that seems not to be available + // on some platforms. + return std::time(nullptr); +} + +} // namespace mlspp diff --git a/mlspp/src/core_types.cpp b/mlspp/src/core_types.cpp new file mode 100755 index 0000000000..19cee0d4c2 --- /dev/null +++ b/mlspp/src/core_types.cpp @@ -0,0 +1,443 @@ +#include "mls/core_types.h" +#include "mls/messages.h" + +#include "grease.h" + +#include + +namespace mlspp { + +/// +/// Extensions +/// + +const Extension::Type RequiredCapabilitiesExtension::type = + ExtensionType::required_capabilities; +const Extension::Type ApplicationIDExtension::type = + ExtensionType::application_id; + +const std::array default_extensions = { + ExtensionType::application_id, ExtensionType::ratchet_tree, + ExtensionType::required_capabilities, ExtensionType::external_pub, + ExtensionType::external_senders, +}; + +const std::array default_proposals = { + ProposalType::add, + ProposalType::update, + ProposalType::remove, + ProposalType::psk, + ProposalType::reinit, + ProposalType::external_init, + ProposalType::group_context_extensions, +}; + +const std::array all_supported_versions = { + ProtocolVersion::mls10 +}; + +const std::array all_supported_ciphersuites = { + CipherSuite::ID::X25519_AES128GCM_SHA256_Ed25519, + CipherSuite::ID::P256_AES128GCM_SHA256_P256, + CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, + CipherSuite::ID::X448_AES256GCM_SHA512_Ed448, + CipherSuite::ID::P521_AES256GCM_SHA512_P521, + CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, +}; + +const std::array all_supported_credentials = { + CredentialType::basic, + CredentialType::x509, + CredentialType::userinfo_vc_draft_00, + CredentialType::multi_draft_00 +}; + +Capabilities +Capabilities::create_default() +{ + return { + { all_supported_versions.begin(), all_supported_versions.end() }, + { all_supported_ciphersuites.begin(), all_supported_ciphersuites.end() }, + { /* No non-default extensions */ }, + { /* No non-default proposals */ }, + { all_supported_credentials.begin(), all_supported_credentials.end() }, + }; +} + +bool +Capabilities::extensions_supported( + const std::vector& required) const +{ + return stdx::all_of(required, [&](Extension::Type type) { + if (stdx::contains(default_extensions, type)) { + return true; + } + + return stdx::contains(extensions, type); + }); +} + +bool +Capabilities::proposals_supported( + const std::vector& required) const +{ + return stdx::all_of(required, [&](Proposal::Type type) { + if (stdx::contains(default_proposals, type)) { + return true; + } + + return stdx::contains(proposals, type); + }); +} + +bool +Capabilities::credential_supported(const Credential& credential) const +{ + return stdx::contains(credentials, credential.type()); +} + +Lifetime +Lifetime::create_default() +{ + return Lifetime{ 0x0000000000000000, 0xffffffffffffffff }; +} + +void +ExtensionList::add(uint16_t type, bytes data) +{ + auto curr = stdx::find_if( + extensions, [&](const Extension& ext) -> bool { return ext.type == type; }); + if (curr != extensions.end()) { + curr->data = std::move(data); + return; + } + + extensions.push_back({ type, std::move(data) }); +} + +bool +ExtensionList::has(uint16_t type) const +{ + return stdx::any_of(extensions, + [&](const Extension& ext) { return ext.type == type; }); +} + +/// +/// LeafNode +/// +LeafNode::LeafNode(CipherSuite cipher_suite, + HPKEPublicKey encryption_key_in, + SignaturePublicKey signature_key_in, + Credential credential_in, + Capabilities capabilities_in, + Lifetime lifetime_in, + ExtensionList extensions_in, + const SignaturePrivateKey& sig_priv) + : encryption_key(std::move(encryption_key_in)) + , signature_key(std::move(signature_key_in)) + , credential(std::move(credential_in)) + , capabilities(std::move(capabilities_in)) + , content(lifetime_in) + , extensions(std::move(extensions_in)) +{ + grease(extensions); + grease(capabilities, extensions); + sign(cipher_suite, sig_priv, std::nullopt); +} + +void +LeafNode::set_capabilities(Capabilities capabilities_in) +{ + capabilities = std::move(capabilities_in); + grease(capabilities, extensions); +} + +LeafNode +LeafNode::for_update(CipherSuite cipher_suite, + const bytes& group_id, + LeafIndex leaf_index, + HPKEPublicKey encryption_key_in, + const LeafNodeOptions& opts, + const SignaturePrivateKey& sig_priv) const +{ + auto clone = clone_with_options(std::move(encryption_key_in), opts); + + clone.content = Empty{}; + clone.sign(cipher_suite, sig_priv, { { group_id, leaf_index } }); + + return clone; +} + +LeafNode +LeafNode::for_commit(CipherSuite cipher_suite, + const bytes& group_id, + LeafIndex leaf_index, + HPKEPublicKey encryption_key_in, + const bytes& parent_hash, + const LeafNodeOptions& opts, + const SignaturePrivateKey& sig_priv) const +{ + auto clone = clone_with_options(std::move(encryption_key_in), opts); + + clone.content = ParentHash{ parent_hash }; + clone.sign(cipher_suite, sig_priv, { { group_id, leaf_index } }); + + return clone; +} + +LeafNodeSource +LeafNode::source() const +{ + return tls::variant::type(content); +} + +void +LeafNode::sign(CipherSuite cipher_suite, + const SignaturePrivateKey& sig_priv, + const std::optional& binding) +{ + const auto tbs = to_be_signed(binding); + + if (sig_priv.public_key != signature_key) { + throw InvalidParameterError("Signature key mismatch"); + } + + if (!credential.valid_for(signature_key)) { + throw InvalidParameterError("Credential not valid for signature key"); + } + + signature = sig_priv.sign(cipher_suite, sign_label::leaf_node, tbs); +} + +bool +LeafNode::verify(CipherSuite cipher_suite, + const std::optional& binding) const +{ + const auto tbs = to_be_signed(binding); + + if (CredentialType::x509 == credential.type()) { + const auto& cred = credential.get(); + if (cred.signature_scheme() != + tls_signature_scheme(cipher_suite.sig().id)) { + throw std::runtime_error("Signature algorithm invalid"); + } + } + + return signature_key.verify( + cipher_suite, sign_label::leaf_node, tbs, signature); +} + +bool +LeafNode::verify_expiry(uint64_t now) const +{ + const auto valid = overloaded{ + [now](const Lifetime& lt) { + return lt.not_before <= now && now <= lt.not_after; + }, + [](const auto& /* other */) { return false; }, + }; + return var::visit(valid, content); +} + +bool +LeafNode::verify_extension_support(const ExtensionList& ext_list) const +{ + // Verify that extensions in the list are supported + auto ext_types = stdx::transform( + ext_list.extensions, [](const auto& ext) { return ext.type; }); + + if (!capabilities.extensions_supported(ext_types)) { + return false; + } + + // If there's a RequiredCapabilities extension, verify support + const auto maybe_req_capas = ext_list.find(); + if (!maybe_req_capas) { + return true; + } + + const auto& req_capas = opt::get(maybe_req_capas); + return capabilities.extensions_supported(req_capas.extensions) && + capabilities.proposals_supported(req_capas.proposals); +} + +LeafNode +LeafNode::clone_with_options(HPKEPublicKey encryption_key_in, + const LeafNodeOptions& opts) const +{ + auto clone = *this; + + clone.encryption_key = std::move(encryption_key_in); + + if (opts.credential) { + clone.credential = opt::get(opts.credential); + } + + if (opts.capabilities) { + clone.capabilities = opt::get(opts.capabilities); + } + + if (opts.extensions) { + clone.extensions = opt::get(opts.extensions); + } + + return clone; +} + +// struct { +// HPKEPublicKey encryption_key; +// SignaturePublicKey signature_key; +// Credential credential; +// Capabilities capabilities; +// +// LeafNodeSource leaf_node_source; +// select (leaf_node_source) { +// case key_package: +// Lifetime lifetime; +// +// case update: +// struct{}; +// +// case commit: +// opaque parent_hash; +// } +// +// Extension extensions; +// +// select (leaf_node_source) { +// case key_package: +// struct{}; +// +// case update: +// opaque group_id; +// +// case commit: +// opaque group_id; +// } +// } LeafNodeTBS; +struct LeafNodeTBS +{ + const HPKEPublicKey& encryption_key; + const SignaturePublicKey& signature_key; + const Credential& credential; + const Capabilities& capabilities; + const var::variant& content; + const ExtensionList& extensions; + + TLS_SERIALIZABLE(encryption_key, + signature_key, + credential, + capabilities, + content, + extensions) + TLS_TRAITS(tls::pass, + tls::pass, + tls::pass, + tls::pass, + tls::variant, + tls::pass) +}; + +bytes +LeafNode::to_be_signed(const std::optional& binding) const +{ + tls::ostream w; + + w << LeafNodeTBS{ + encryption_key, signature_key, credential, + capabilities, content, extensions, + }; + + switch (source()) { + case LeafNodeSource::key_package: + break; + + case LeafNodeSource::update: + case LeafNodeSource::commit: + w << opt::get(binding); + } + + return w.bytes(); +} + +/// +/// NodeType, ParentNode, and KeyPackage +/// + +bytes +ParentNode::hash(CipherSuite suite) const +{ + return suite.digest().hash(tls::marshal(this)); +} + +KeyPackage::KeyPackage() + : version(ProtocolVersion::mls10) + , cipher_suite(CipherSuite::ID::unknown) +{ +} + +KeyPackage::KeyPackage(CipherSuite suite_in, + HPKEPublicKey init_key_in, + LeafNode leaf_node_in, + ExtensionList extensions_in, + const SignaturePrivateKey& sig_priv_in) + : version(ProtocolVersion::mls10) + , cipher_suite(suite_in) + , init_key(std::move(init_key_in)) + , leaf_node(std::move(leaf_node_in)) + , extensions(std::move(extensions_in)) +{ + grease(extensions); + sign(sig_priv_in); +} + +KeyPackageRef +KeyPackage::ref() const +{ + return cipher_suite.ref(*this); +} + +void +KeyPackage::sign(const SignaturePrivateKey& sig_priv) +{ + auto tbs = to_be_signed(); + signature = sig_priv.sign(cipher_suite, sign_label::key_package, tbs); +} + +bool +KeyPackage::verify() const +{ + // Verify the inner leaf node + if (!leaf_node.verify(cipher_suite, std::nullopt)) { + return false; + } + + // Check that the inner leaf node is intended for use in a KeyPackage + if (leaf_node.source() != LeafNodeSource::key_package) { + return false; + } + + // Verify the KeyPackage + const auto tbs = to_be_signed(); + + if (CredentialType::x509 == leaf_node.credential.type()) { + const auto& cred = leaf_node.credential.get(); + if (cred.signature_scheme() != + tls_signature_scheme(cipher_suite.sig().id)) { + throw std::runtime_error("Signature algorithm invalid"); + } + } + + return leaf_node.signature_key.verify( + cipher_suite, sign_label::key_package, tbs, signature); +} + +bytes +KeyPackage::to_be_signed() const +{ + tls::ostream out; + out << version << cipher_suite << init_key << leaf_node << extensions; + return out.bytes(); +} + +} // namespace mlspp diff --git a/mlspp/src/credential.cpp b/mlspp/src/credential.cpp new file mode 100755 index 0000000000..4edb3a9b82 --- /dev/null +++ b/mlspp/src/credential.cpp @@ -0,0 +1,298 @@ +#include +#include +#include +#include + +namespace mlspp { + +/// +/// X509Credential +/// + +using mlspp::hpke::Certificate; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::Signature; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::UserInfoVC; // NOLINT(misc-unused-using-decls) + +static const Signature& +find_signature(Signature::ID id) +{ + switch (id) { + case Signature::ID::P256_SHA256: + return Signature::get(); + case Signature::ID::P384_SHA384: + return Signature::get(); + case Signature::ID::P521_SHA512: + return Signature::get(); + case Signature::ID::Ed25519: + return Signature::get(); +#if !defined(WITH_BORINGSSL) + case Signature::ID::Ed448: + return Signature::get(); +#endif + case Signature::ID::RSA_SHA256: + return Signature::get(); + default: + throw InvalidParameterError("Unsupported algorithm"); + } +} + +static std::vector +bytes_to_x509_credential_data(const std::vector& data_in) +{ + return stdx::transform( + data_in, [](const bytes& der) { return X509Credential::CertData{ der }; }); +} + +X509Credential::X509Credential(const std::vector& der_chain_in) + : der_chain(bytes_to_x509_credential_data(der_chain_in)) +{ + if (der_chain.empty()) { + throw std::invalid_argument("empty certificate chain"); + } + + // Parse the chain + auto parsed = std::vector(); + for (const auto& cert : der_chain) { + parsed.emplace_back(cert.data); + } + + // first element represents leaf cert + const auto& sig = find_signature(parsed[0].public_key_algorithm()); + const auto pub_data = sig.serialize(*parsed[0].public_key); + _signature_scheme = tls_signature_scheme(parsed[0].public_key_algorithm()); + _public_key = SignaturePublicKey{ pub_data }; + + // verify chain for valid signatures + for (size_t i = 0; i < der_chain.size() - 1; i++) { + if (!parsed[i].valid_from(parsed[i + 1])) { + throw std::runtime_error("Certificate Chain validation failure"); + } + } +} + +SignatureScheme +X509Credential::signature_scheme() const +{ + return _signature_scheme; +} + +SignaturePublicKey +X509Credential::public_key() const +{ + return _public_key; +} + +bool +X509Credential::valid_for(const SignaturePublicKey& pub) const +{ + return pub == public_key(); +} + +tls::ostream& +operator<<(tls::ostream& str, const X509Credential& obj) +{ + return str << obj.der_chain; +} + +tls::istream& +operator>>(tls::istream& str, X509Credential& obj) +{ + auto der_chain = std::vector{}; + str >> der_chain; + + auto der_in = stdx::transform( + der_chain, [](const auto& cert_data) { return cert_data.data; }); + obj = X509Credential(der_in); + + return str; +} + +bool +operator==(const X509Credential& lhs, const X509Credential& rhs) +{ + return lhs.der_chain == rhs.der_chain; +} + +/// +/// UserInfoVCCredential +/// +UserInfoVCCredential::UserInfoVCCredential(std::string userinfo_vc_jwt_in) + : userinfo_vc_jwt(std::move(userinfo_vc_jwt_in)) + , _vc(std::make_shared(userinfo_vc_jwt)) +{ +} + +bool +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +UserInfoVCCredential::valid_for(const SignaturePublicKey& pub) const +{ + const auto& vc_pub = _vc->public_key(); + return pub.data == vc_pub.sig.serialize(*vc_pub.key); +} + +bool +UserInfoVCCredential::valid_from(const PublicJWK& pub) const +{ + const auto& sig = _vc->signature_algorithm(); + if (pub.signature_scheme != tls_signature_scheme(sig.id)) { + return false; + } + + const auto sig_pub = sig.deserialize(pub.public_key.data); + return _vc->valid_from(*sig_pub); +} + +tls::ostream +operator<<(tls::ostream& str, const UserInfoVCCredential& obj) +{ + return str << from_ascii(obj.userinfo_vc_jwt); +} + +tls::istream +operator>>(tls::istream& str, UserInfoVCCredential& obj) +{ + auto jwt = bytes{}; + str >> jwt; + obj = UserInfoVCCredential(to_ascii(jwt)); + return str; +} + +bool +operator==(const UserInfoVCCredential& lhs, const UserInfoVCCredential& rhs) +{ + return lhs.userinfo_vc_jwt == rhs.userinfo_vc_jwt; +} + +bool +operator!=(const UserInfoVCCredential& lhs, const UserInfoVCCredential& rhs) +{ + return !(lhs == rhs); +} + +/// +/// CredentialBinding and MultiCredential +/// + +struct CredentialBindingTBS +{ + const CipherSuite& cipher_suite; + const Credential& credential; + const SignaturePublicKey& credential_key; + const SignaturePublicKey& signature_key; + + TLS_SERIALIZABLE(cipher_suite, credential, credential_key, signature_key) +}; + +CredentialBinding::CredentialBinding(CipherSuite cipher_suite_in, + Credential credential_in, + const SignaturePrivateKey& credential_priv, + const SignaturePublicKey& signature_key) + : cipher_suite(cipher_suite_in) + , credential(std::move(credential_in)) + , credential_key(credential_priv.public_key) +{ + if (credential.type() == CredentialType::multi_draft_00) { + throw InvalidParameterError("Multi-credentials cannot be nested"); + } + + if (!credential.valid_for(credential_key)) { + throw InvalidParameterError("Credential key does not match credential"); + } + + signature = credential_priv.sign( + cipher_suite, sign_label::multi_credential, to_be_signed(signature_key)); +} + +bytes +CredentialBinding::to_be_signed(const SignaturePublicKey& signature_key) const +{ + return tls::marshal(CredentialBindingTBS{ + cipher_suite, credential, credential_key, signature_key }); +} + +bool +CredentialBinding::valid_for(const SignaturePublicKey& signature_key) const +{ + auto valid_self = credential.valid_for(credential_key); + auto valid_other = credential_key.verify(cipher_suite, + sign_label::multi_credential, + to_be_signed(signature_key), + signature); + + return valid_self && valid_other; +} + +MultiCredential::MultiCredential( + const std::vector& binding_inputs, + const SignaturePublicKey& signature_key) +{ + bindings = + stdx::transform(binding_inputs, [&](auto&& input) { + return CredentialBinding(input.cipher_suite, + input.credential, + input.credential_priv, + signature_key); + }); +} + +bool +MultiCredential::valid_for(const SignaturePublicKey& pub) const +{ + return stdx::all_of( + bindings, [&](const auto& binding) { return binding.valid_for(pub); }); +} + +/// +/// Credential +/// + +CredentialType +Credential::type() const +{ + return tls::variant::type(_cred); +} + +Credential +Credential::basic(const bytes& identity) +{ + return { BasicCredential{ identity } }; +} + +Credential +Credential::x509(const std::vector& der_chain) +{ + return { X509Credential{ der_chain } }; +} + +Credential +Credential::multi(const std::vector& binding_inputs, + const SignaturePublicKey& signature_key) +{ + return { MultiCredential{ binding_inputs, signature_key } }; +} + +Credential +Credential::userinfo_vc(const std::string& userinfo_vc_jwt) +{ + return { UserInfoVCCredential{ userinfo_vc_jwt } }; +} + +bool +Credential::valid_for(const SignaturePublicKey& pub) const +{ + const auto pub_key_match = overloaded{ + [&](const X509Credential& x509) { return x509.valid_for(pub); }, + [](const BasicCredential& /* basic */) { return true; }, + [&](const UserInfoVCCredential& vc) { return vc.valid_for(pub); }, + [&](const MultiCredential& multi) { return multi.valid_for(pub); }, + }; + + return var::visit(pub_key_match, _cred); +} + +Credential::Credential(SpecificCredential specific) + : _cred(std::move(specific)) +{ +} + +} // namespace mlspp diff --git a/mlspp/src/crypto.cpp b/mlspp/src/crypto.cpp new file mode 100755 index 0000000000..5126036acd --- /dev/null +++ b/mlspp/src/crypto.cpp @@ -0,0 +1,498 @@ +#include +#include +#include + +#include + +using mlspp::hpke::AEAD; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::Digest; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::HPKE; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::KDF; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::KEM; // NOLINT(misc-unused-using-decls) +using mlspp::hpke::Signature; // NOLINT(misc-unused-using-decls) + +namespace mlspp { + +SignatureScheme +tls_signature_scheme(Signature::ID id) +{ + switch (id) { + case Signature::ID::P256_SHA256: + return SignatureScheme::ecdsa_secp256r1_sha256; + case Signature::ID::P384_SHA384: + return SignatureScheme::ecdsa_secp384r1_sha384; + case Signature::ID::P521_SHA512: + return SignatureScheme::ecdsa_secp521r1_sha512; + case Signature::ID::Ed25519: + return SignatureScheme::ed25519; +#if !defined(WITH_BORINGSSL) + case Signature::ID::Ed448: + return SignatureScheme::ed448; +#endif + case Signature::ID::RSA_SHA256: + return SignatureScheme::rsa_pkcs1_sha256; + default: + throw InvalidParameterError("Unsupported algorithm"); + } +} + +/// +/// CipherSuites and details +/// + +CipherSuite::CipherSuite() + : id(ID::unknown) +{ +} + +CipherSuite::CipherSuite(ID id_in) + : id(id_in) +{ +} + +SignatureScheme +CipherSuite::signature_scheme() const +{ + switch (id) { + case ID::X25519_AES128GCM_SHA256_Ed25519: + case ID::X25519_CHACHA20POLY1305_SHA256_Ed25519: + return SignatureScheme::ed25519; + case ID::P256_AES128GCM_SHA256_P256: + return SignatureScheme::ecdsa_secp256r1_sha256; + case ID::X448_AES256GCM_SHA512_Ed448: + case ID::X448_CHACHA20POLY1305_SHA512_Ed448: + return SignatureScheme::ed448; + case ID::P521_AES256GCM_SHA512_P521: + return SignatureScheme::ecdsa_secp521r1_sha512; + case ID::P384_AES256GCM_SHA384_P384: + return SignatureScheme::ecdsa_secp384r1_sha384; + default: + throw InvalidParameterError("Unsupported algorithm"); + } +} + +const CipherSuite::Ciphers& +CipherSuite::get() const +{ + static const auto ciphers_X25519_AES128GCM_SHA256_Ed25519 = + CipherSuite::Ciphers{ + HPKE(KEM::ID::DHKEM_X25519_SHA256, + KDF::ID::HKDF_SHA256, + AEAD::ID::AES_128_GCM), + Digest::get(), + Signature::get(), + }; + + static const auto ciphers_P256_AES128GCM_SHA256_P256 = CipherSuite::Ciphers{ + HPKE( + KEM::ID::DHKEM_P256_SHA256, KDF::ID::HKDF_SHA256, AEAD::ID::AES_128_GCM), + Digest::get(), + Signature::get(), + }; + + static const auto ciphers_X25519_CHACHA20POLY1305_SHA256_Ed25519 = + CipherSuite::Ciphers{ + HPKE(KEM::ID::DHKEM_X25519_SHA256, + KDF::ID::HKDF_SHA256, + AEAD::ID::CHACHA20_POLY1305), + Digest::get(), + Signature::get(), + }; + + static const auto ciphers_P521_AES256GCM_SHA512_P521 = CipherSuite::Ciphers{ + HPKE( + KEM::ID::DHKEM_P521_SHA512, KDF::ID::HKDF_SHA512, AEAD::ID::AES_256_GCM), + Digest::get(), + Signature::get(), + }; + + static const auto ciphers_P384_AES256GCM_SHA384_P384 = CipherSuite::Ciphers{ + HPKE( + KEM::ID::DHKEM_P384_SHA384, KDF::ID::HKDF_SHA384, AEAD::ID::AES_256_GCM), + Digest::get(), + Signature::get(), + }; + +#if !defined(WITH_BORINGSSL) + static const auto ciphers_X448_AES256GCM_SHA512_Ed448 = CipherSuite::Ciphers{ + HPKE( + KEM::ID::DHKEM_X448_SHA512, KDF::ID::HKDF_SHA512, AEAD::ID::AES_256_GCM), + Digest::get(), + Signature::get(), + }; + + static const auto ciphers_X448_CHACHA20POLY1305_SHA512_Ed448 = + CipherSuite::Ciphers{ + HPKE(KEM::ID::DHKEM_X448_SHA512, + KDF::ID::HKDF_SHA512, + AEAD::ID::CHACHA20_POLY1305), + Digest::get(), + Signature::get(), + }; +#endif + + switch (id) { + case ID::unknown: + throw InvalidParameterError("Uninitialized ciphersuite"); + + case ID::X25519_AES128GCM_SHA256_Ed25519: + return ciphers_X25519_AES128GCM_SHA256_Ed25519; + + case ID::P256_AES128GCM_SHA256_P256: + return ciphers_P256_AES128GCM_SHA256_P256; + + case ID::X25519_CHACHA20POLY1305_SHA256_Ed25519: + return ciphers_X25519_CHACHA20POLY1305_SHA256_Ed25519; + + case ID::P521_AES256GCM_SHA512_P521: + return ciphers_P521_AES256GCM_SHA512_P521; + + case ID::P384_AES256GCM_SHA384_P384: + return ciphers_P384_AES256GCM_SHA384_P384; + +#if !defined(WITH_BORINGSSL) + case ID::X448_AES256GCM_SHA512_Ed448: + return ciphers_X448_AES256GCM_SHA512_Ed448; + + case ID::X448_CHACHA20POLY1305_SHA512_Ed448: + return ciphers_X448_CHACHA20POLY1305_SHA512_Ed448; +#endif + + default: + throw InvalidParameterError("Unsupported ciphersuite"); + } +} + +struct HKDFLabel +{ + uint16_t length; + bytes label; + bytes context; + + TLS_SERIALIZABLE(length, label, context) +}; + +bytes +CipherSuite::expand_with_label(const bytes& secret, + const std::string& label, + const bytes& context, + size_t length) const +{ + auto mls_label = from_ascii(std::string("MLS 1.0 ") + label); + auto length16 = static_cast(length); + auto label_bytes = tls::marshal(HKDFLabel{ length16, mls_label, context }); + return get().hpke.kdf.expand(secret, label_bytes, length); +} + +bytes +CipherSuite::derive_secret(const bytes& secret, const std::string& label) const +{ + return expand_with_label(secret, label, {}, secret_size()); +} + +bytes +CipherSuite::derive_tree_secret(const bytes& secret, + const std::string& label, + uint32_t generation, + size_t length) const +{ + return expand_with_label(secret, label, tls::marshal(generation), length); +} + +#if WITH_BORINGSSL +const std::array all_supported_suites = { + CipherSuite::ID::X25519_AES128GCM_SHA256_Ed25519, + CipherSuite::ID::P256_AES128GCM_SHA256_P256, + CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, + CipherSuite::ID::P521_AES256GCM_SHA512_P521, + CipherSuite::ID::P384_AES256GCM_SHA384_P384, +}; +#else +const std::array all_supported_suites = { + CipherSuite::ID::X25519_AES128GCM_SHA256_Ed25519, + CipherSuite::ID::P256_AES128GCM_SHA256_P256, + CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, + CipherSuite::ID::P521_AES256GCM_SHA512_P521, + CipherSuite::ID::P384_AES256GCM_SHA384_P384, + CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, + CipherSuite::ID::X448_AES256GCM_SHA512_Ed448, +}; +#endif + +// MakeKeyPackageRef(value) = KDF.expand( +// KDF.extract("", value), "MLS 1.0 KeyPackage Reference", 16) +template<> +const bytes& +CipherSuite::reference_label() +{ + static const auto label = from_ascii("MLS 1.0 KeyPackage Reference"); + return label; +} + +// MakeProposalRef(value) = KDF.expand( +// KDF.extract("", value), "MLS 1.0 Proposal Reference", 16) +// +// Even though the label says "Proposal", we actually hash the entire enclosing +// AuthenticatedContent object. +template<> +const bytes& +CipherSuite::reference_label() +{ + static const auto label = from_ascii("MLS 1.0 Proposal Reference"); + return label; +} + +/// +/// HPKEPublicKey and HPKEPrivateKey +/// + +// This function produces a non-literal type, so it can't be constexpr. +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define MLS_1_0_PLUS(label) from_ascii("MLS 1.0 " label) + +static bytes +mls_1_0_plus(const std::string& label) +{ + auto plus = "MLS 1.0 "s + label; + return from_ascii(plus); +} + +namespace encrypt_label { +const std::string update_path_node = "UpdatePathNode"; +const std::string welcome = "Welcome"; +} // namespace encrypt_label + +struct EncryptContext +{ + const bytes& label; + const bytes& content; + TLS_SERIALIZABLE(label, content) +}; + +HPKECiphertext +HPKEPublicKey::encrypt(CipherSuite suite, + const std::string& label, + const bytes& context, + const bytes& pt) const +{ + auto label_plus = mls_1_0_plus(label); + auto encrypt_context = tls::marshal(EncryptContext{ label_plus, context }); + auto pkR = suite.hpke().kem.deserialize(data); + auto [enc, ctx] = suite.hpke().setup_base_s(*pkR, encrypt_context); + auto ct = ctx.seal({}, pt); + return HPKECiphertext{ enc, ct }; +} + +std::tuple +HPKEPublicKey::do_export(CipherSuite suite, + const bytes& info, + const std::string& label, + size_t size) const +{ + auto label_data = from_ascii(label); + auto pkR = suite.hpke().kem.deserialize(data); + auto [enc, ctx] = suite.hpke().setup_base_s(*pkR, info); + auto exported = ctx.do_export(label_data, size); + return std::make_tuple(enc, exported); +} + +HPKEPrivateKey +HPKEPrivateKey::generate(CipherSuite suite) +{ + auto priv = suite.hpke().kem.generate_key_pair(); + auto priv_data = suite.hpke().kem.serialize_private(*priv); + auto pub = priv->public_key(); + auto pub_data = suite.hpke().kem.serialize(*pub); + return { priv_data, pub_data }; +} + +HPKEPrivateKey +HPKEPrivateKey::parse(CipherSuite suite, const bytes& data) +{ + auto priv = suite.hpke().kem.deserialize_private(data); + auto pub = priv->public_key(); + auto pub_data = suite.hpke().kem.serialize(*pub); + return { data, pub_data }; +} + +HPKEPrivateKey +HPKEPrivateKey::derive(CipherSuite suite, const bytes& secret) +{ + auto priv = suite.hpke().kem.derive_key_pair(secret); + auto priv_data = suite.hpke().kem.serialize_private(*priv); + auto pub = priv->public_key(); + auto pub_data = suite.hpke().kem.serialize(*pub); + return { priv_data, pub_data }; +} + +bytes +HPKEPrivateKey::decrypt(CipherSuite suite, + const std::string& label, + const bytes& context, + const HPKECiphertext& ct) const +{ + auto label_plus = mls_1_0_plus(label); + auto encrypt_context = tls::marshal(EncryptContext{ label_plus, context }); + auto skR = suite.hpke().kem.deserialize_private(data); + auto ctx = suite.hpke().setup_base_r(ct.kem_output, *skR, encrypt_context); + auto pt = ctx.open({}, ct.ciphertext); + if (!pt) { + throw InvalidParameterError("HPKE decryption failure"); + } + + return opt::get(pt); +} + +bytes +HPKEPrivateKey::do_export(CipherSuite suite, + const bytes& info, + const bytes& kem_output, + const std::string& label, + size_t size) const +{ + auto label_data = from_ascii(label); + auto skR = suite.hpke().kem.deserialize_private(data); + auto ctx = suite.hpke().setup_base_r(kem_output, *skR, info); + return ctx.do_export(label_data, size); +} + +HPKEPrivateKey::HPKEPrivateKey(bytes priv_data, bytes pub_data) + : data(std::move(priv_data)) + , public_key{ std::move(pub_data) } +{ +} + +void +HPKEPrivateKey::set_public_key(CipherSuite suite) +{ + const auto priv = suite.hpke().kem.deserialize_private(data); + auto pub = priv->public_key(); + public_key.data = suite.hpke().kem.serialize(*pub); +} + +/// +/// SignaturePublicKey and SignaturePrivateKey +/// +namespace sign_label { +const std::string mls_content = "FramedContentTBS"; +const std::string leaf_node = "LeafNodeTBS"; +const std::string key_package = "KeyPackageTBS"; +const std::string group_info = "GroupInfoTBS"; +const std::string multi_credential = "MultiCredential"; +} // namespace sign_label + +struct SignContent +{ + const bytes& label; + const bytes& content; + TLS_SERIALIZABLE(label, content) +}; + +bool +SignaturePublicKey::verify(const CipherSuite& suite, + const std::string& label, + const bytes& message, + const bytes& signature) const +{ + auto label_plus = mls_1_0_plus(label); + const auto content = tls::marshal(SignContent{ label_plus, message }); + auto pub = suite.sig().deserialize(data); + return suite.sig().verify(content, signature, *pub); +} + +SignaturePublicKey +SignaturePublicKey::from_jwk(CipherSuite suite, const std::string& json_str) +{ + auto pub = suite.sig().import_jwk(json_str); + auto pub_data = suite.sig().serialize(*pub); + return SignaturePublicKey{ pub_data }; +} + +std::string +SignaturePublicKey::to_jwk(CipherSuite suite) const +{ + auto pub = suite.sig().deserialize(data); + return suite.sig().export_jwk(*pub); +} + +PublicJWK +PublicJWK::parse(const std::string& jwk_json) +{ + const auto parsed = Signature::parse_jwk(jwk_json); + const auto scheme = tls_signature_scheme(parsed.sig.id); + const auto pub_data = parsed.sig.serialize(*parsed.key); + return { scheme, parsed.key_id, { pub_data } }; +} + +SignaturePrivateKey +SignaturePrivateKey::generate(CipherSuite suite) +{ + auto priv = suite.sig().generate_key_pair(); + auto priv_data = suite.sig().serialize_private(*priv); + auto pub = priv->public_key(); + auto pub_data = suite.sig().serialize(*pub); + return { priv_data, pub_data }; +} + +SignaturePrivateKey +SignaturePrivateKey::parse(CipherSuite suite, const bytes& data) +{ + auto priv = suite.sig().deserialize_private(data); + auto pub = priv->public_key(); + auto pub_data = suite.sig().serialize(*pub); + return { data, pub_data }; +} + +SignaturePrivateKey +SignaturePrivateKey::derive(CipherSuite suite, const bytes& secret) +{ + auto priv = suite.sig().derive_key_pair(secret); + auto priv_data = suite.sig().serialize_private(*priv); + auto pub = priv->public_key(); + auto pub_data = suite.sig().serialize(*pub); + return { priv_data, pub_data }; +} + +bytes +SignaturePrivateKey::sign(const CipherSuite& suite, + const std::string& label, + const bytes& message) const +{ + auto label_plus = mls_1_0_plus(label); + const auto content = tls::marshal(SignContent{ label_plus, message }); + const auto priv = suite.sig().deserialize_private(data); + return suite.sig().sign(content, *priv); +} + +SignaturePrivateKey::SignaturePrivateKey(bytes priv_data, bytes pub_data) + : data(std::move(priv_data)) + , public_key{ std::move(pub_data) } +{ +} + +void +SignaturePrivateKey::set_public_key(CipherSuite suite) +{ + const auto priv = suite.sig().deserialize_private(data); + auto pub = priv->public_key(); + public_key.data = suite.sig().serialize(*pub); +} + +SignaturePrivateKey +SignaturePrivateKey::from_jwk(CipherSuite suite, const std::string& json_str) +{ + auto priv = suite.sig().import_jwk_private(json_str); + auto priv_data = suite.sig().serialize_private(*priv); + auto pub = priv->public_key(); + auto pub_data = suite.sig().serialize(*pub); + return { priv_data, pub_data }; +} + +std::string +SignaturePrivateKey::to_jwk(CipherSuite suite) const +{ + const auto priv = suite.sig().deserialize_private(data); + return suite.sig().export_jwk_private(*priv); +} + +} // namespace mlspp diff --git a/mlspp/src/grease.cpp b/mlspp/src/grease.cpp new file mode 100755 index 0000000000..05aaddbe9e --- /dev/null +++ b/mlspp/src/grease.cpp @@ -0,0 +1,126 @@ +#include "grease.h" + +#include +#include + +namespace mlspp { + +#ifdef DISABLE_GREASE + +void +grease([[maybe_unused]] Capabilities& capabilities, + [[maybe_unused]] const ExtensionList& extensions) +{ +} + +void +grease([[maybe_unused]] ExtensionList& extensions) +{ +} + +#else + +// Randomness parmeters: +// * Given a list of N items, insert max(1, rand(p_grease * N)) GREASE values +// * Each GREASE value added is distinct, unless more than 15 values are needed +// * For extensions, each GREASE extension has rand(n_grease_ext) random bytes +// of data +const size_t log_p_grease = 1; // -log2(p_grease) => p_grease = 1/2 +const size_t max_grease_ext_size = 16; + +const std::array grease_values = { 0x0A0A, 0x1A1A, 0x2A2A, 0x3A3A, + 0x4A4A, 0x5A5A, 0x6A6A, 0x7A7A, + 0x8A8A, 0x9A9A, 0xAAAA, 0xBABA, + 0xCACA, 0xDADA, 0xEAEA }; + +static size_t +rand_int(size_t n) +{ + static auto seed = std::random_device()(); + static auto rng = std::mt19937(seed); + return std::uniform_int_distribution(0, n)(rng); +} + +static uint16_t +grease_value() +{ + const auto where = rand_int(grease_values.size() - 1); + return grease_values.at(where); +} + +static bool +grease_value(uint16_t val) +{ + static constexpr auto grease_mask = uint16_t(0x0F0F); + return ((val & grease_mask) == 0x0A0A) && val != 0xFAFA; +} + +static std::set +grease_sample(size_t count) +{ + auto vals = std::set{}; + + while (vals.size() < count) { + uint16_t val = grease_value(); + while (vals.count(val) > 0 && vals.size() < grease_values.size()) { + val = grease_value(); + } + + vals.insert(val); + } + + return vals; +} + +template +static void +grease(std::vector& vec) +{ + const auto count = std::max(size_t(1), rand_int(vec.size() >> log_p_grease)); + for (const auto val : grease_sample(count)) { + const auto where = static_cast(rand_int(vec.size())); + vec.insert(std::begin(vec) + where, static_cast(val)); + } +} + +void +grease(Capabilities& capabilities, const ExtensionList& extensions) +{ + // Add GREASE to the appropriate portions of the capabilities + grease(capabilities.cipher_suites); + grease(capabilities.extensions); + grease(capabilities.proposals); + grease(capabilities.credentials); + + // Ensure that the GREASE extensions are reflected in Capabilities.extensions + for (const auto& ext : extensions.extensions) { + if (!grease_value(ext.type)) { + continue; + } + + if (stdx::contains(capabilities.extensions, ext.type)) { + continue; + } + + const auto where = + static_cast(rand_int(capabilities.extensions.size())); + const auto where_ptr = std::begin(capabilities.extensions) + where; + capabilities.extensions.insert(where_ptr, ext.type); + } +} + +void +grease(ExtensionList& extensions) +{ + auto& ext = extensions.extensions; + const auto count = std::max(size_t(1), rand_int(ext.size() >> log_p_grease)); + for (const auto ext_type : grease_sample(count)) { + const auto where = static_cast(rand_int(ext.size())); + auto ext_data = random_bytes(rand_int(max_grease_ext_size)); + ext.insert(std::begin(ext) + where, { ext_type, std::move(ext_data) }); + } +} + +#endif // DISABLE_GREASE + +} // namespace mlspp diff --git a/mlspp/src/grease.h b/mlspp/src/grease.h new file mode 100755 index 0000000000..94ed157eed --- /dev/null +++ b/mlspp/src/grease.h @@ -0,0 +1,13 @@ +#pragma once + +#include "mls/core_types.h" + +namespace mlspp { + +void +grease(Capabilities& capabilities, const ExtensionList& extensions); + +void +grease(ExtensionList& extensions); + +} // namespace mlspp diff --git a/mlspp/src/key_schedule.cpp b/mlspp/src/key_schedule.cpp new file mode 100755 index 0000000000..7a5788103e --- /dev/null +++ b/mlspp/src/key_schedule.cpp @@ -0,0 +1,579 @@ +#include + +namespace mlspp { + +/// +/// Key Derivation Functions +/// + +struct TreeContext +{ + NodeIndex node; + uint32_t generation = 0; + + TLS_SERIALIZABLE(node, generation) +}; + +/// +/// HashRatchet +/// + +HashRatchet::HashRatchet(CipherSuite suite_in, bytes base_secret_in) + : suite(suite_in) + , next_secret(std::move(base_secret_in)) + , next_generation(0) + , key_size(suite.hpke().aead.key_size) + , nonce_size(suite.hpke().aead.nonce_size) + , secret_size(suite.secret_size()) +{ +} + +std::tuple +HashRatchet::next() +{ + auto generation = next_generation; + auto key = suite.derive_tree_secret(next_secret, "key", generation, key_size); + auto nonce = + suite.derive_tree_secret(next_secret, "nonce", generation, nonce_size); + auto secret = + suite.derive_tree_secret(next_secret, "secret", generation, secret_size); + + next_generation += 1; + next_secret = secret; + + cache[generation] = { key, nonce }; + return { generation, cache.at(generation) }; +} + +// Note: This construction deliberately does not preserve the forward-secrecy +// invariant, in that keys/nonces are not deleted after they are used. +// Otherwise, it would not be possible for a node to send to itself. Keys can +// be deleted once they are not needed by calling HashRatchet::erase(). +KeyAndNonce +HashRatchet::get(uint32_t generation) +{ + if (cache.count(generation) > 0) { + auto out = cache.at(generation); + return out; + } + + if (next_generation > generation) { + throw ProtocolError("Request for expired key"); + } + + while (next_generation <= generation) { + next(); + } + + return cache.at(generation); +} + +void +HashRatchet::erase(uint32_t generation) +{ + if (cache.count(generation) == 0) { + return; + } + + cache.erase(generation); +} + +/// +/// SecretTree +/// + +SecretTree::SecretTree(CipherSuite suite_in, + LeafCount group_size_in, + bytes encryption_secret_in) + : suite(suite_in) + , group_size(LeafCount::full(group_size_in)) + , root(NodeIndex::root(group_size)) + , secret_size(suite_in.secret_size()) +{ + secrets.emplace(root, std::move(encryption_secret_in)); +} + +bytes +SecretTree::get(LeafIndex sender) +{ + static const auto context_left = from_ascii("left"); + static const auto context_right = from_ascii("right"); + auto node = NodeIndex(sender); + + // Find an ancestor that is populated + auto dirpath = node.dirpath(group_size); + dirpath.insert(dirpath.begin(), node); + dirpath.push_back(root); + uint32_t curr = 0; + for (; curr < dirpath.size(); ++curr) { + auto i = dirpath.at(curr); + if (secrets.count(i) > 0) { + break; + } + } + + if (curr > dirpath.size()) { + throw InvalidParameterError("No secret found to derive base key"); + } + + // Derive down + for (; curr > 0; --curr) { + auto curr_node = dirpath.at(curr); + auto left = curr_node.left(); + auto right = curr_node.right(); + + auto& secret = secrets.at(curr_node); + + const auto left_secret = + suite.expand_with_label(secret, "tree", context_left, secret_size); + const auto right_secret = + suite.expand_with_label(secret, "tree", context_right, secret_size); + + secrets.insert_or_assign(left, left_secret); + secrets.insert_or_assign(right, right_secret); + } + + // Copy the leaf + auto out = secrets.at(node); + + // Zeroize along the direct path + for (auto i : dirpath) { + secrets.erase(i); + } + + return out; +} + +/// +/// ReuseGuard +/// + +static ReuseGuard +new_reuse_guard() +{ + auto random = random_bytes(4); + auto guard = ReuseGuard(); + std::copy(random.begin(), random.end(), guard.begin()); + return guard; +} + +static void +apply_reuse_guard(const ReuseGuard& guard, bytes& nonce) +{ + for (size_t i = 0; i < guard.size(); i++) { + nonce.at(i) ^= guard.at(i); + } +} + +/// +/// GroupKeySource +/// + +GroupKeySource::GroupKeySource(CipherSuite suite_in, + LeafCount group_size, + bytes encryption_secret) + : suite(suite_in) + , secret_tree(suite, group_size, std::move(encryption_secret)) +{ +} + +HashRatchet& +GroupKeySource::chain(ContentType type, LeafIndex sender) +{ + switch (type) { + case ContentType::proposal: + case ContentType::commit: + return chain(RatchetType::handshake, sender); + + case ContentType::application: + return chain(RatchetType::application, sender); + + default: + throw InvalidParameterError("Invalid content type"); + } +} + +HashRatchet& +GroupKeySource::chain(RatchetType type, LeafIndex sender) +{ + auto key = Key{ type, sender }; + if (chains.count(key) > 0) { + return chains[key]; + } + + auto secret_size = suite.secret_size(); + auto leaf_secret = secret_tree.get(sender); + + auto handshake_secret = + suite.expand_with_label(leaf_secret, "handshake", {}, secret_size); + auto application_secret = + suite.expand_with_label(leaf_secret, "application", {}, secret_size); + + chains.emplace(Key{ RatchetType::handshake, sender }, + HashRatchet{ suite, handshake_secret }); + chains.emplace(Key{ RatchetType::application, sender }, + HashRatchet{ suite, application_secret }); + + return chains[key]; +} + +std::tuple +GroupKeySource::next(ContentType type, LeafIndex sender) +{ + auto [generation, keys] = chain(type, sender).next(); + + auto reuse_guard = new_reuse_guard(); + apply_reuse_guard(reuse_guard, keys.nonce); + + return { generation, reuse_guard, keys }; +} + +KeyAndNonce +GroupKeySource::get(ContentType type, + LeafIndex sender, + uint32_t generation, + ReuseGuard reuse_guard) +{ + auto keys = chain(type, sender).get(generation); + apply_reuse_guard(reuse_guard, keys.nonce); + return keys; +} + +void +GroupKeySource::erase(ContentType type, LeafIndex sender, uint32_t generation) +{ + return chain(type, sender).erase(generation); +} + +// struct { +// opaque group_id<0..255>; +// uint64 epoch; +// ContentType content_type; +// opaque authenticated_data<0..2^32-1>; +// } ContentAAD; +struct ContentAAD +{ + const bytes& group_id; + const epoch_t epoch; + const ContentType content_type; + const bytes& authenticated_data; + + TLS_SERIALIZABLE(group_id, epoch, content_type, authenticated_data) +}; + +/// +/// KeyScheduleEpoch +/// + +struct PSKLabel +{ + const PreSharedKeyID& id; + uint16_t index; + uint16_t count; + + TLS_SERIALIZABLE(id, index, count); +}; + +static bytes +make_joiner_secret(CipherSuite suite, + const bytes& context, + const bytes& init_secret, + const bytes& commit_secret) +{ + auto pre_joiner_secret = suite.hpke().kdf.extract(init_secret, commit_secret); + return suite.expand_with_label( + pre_joiner_secret, "joiner", context, suite.secret_size()); +} + +static bytes +make_epoch_secret(CipherSuite suite, + const bytes& joiner_secret, + const bytes& psk_secret, + const bytes& context) +{ + auto member_secret = suite.hpke().kdf.extract(joiner_secret, psk_secret); + return suite.expand_with_label( + member_secret, "epoch", context, suite.secret_size()); +} + +KeyScheduleEpoch +KeyScheduleEpoch::joiner(CipherSuite suite_in, + const bytes& joiner_secret, + const std::vector& psks, + const bytes& context) +{ + return { suite_in, joiner_secret, make_psk_secret(suite_in, psks), context }; +} + +KeyScheduleEpoch::KeyScheduleEpoch(CipherSuite suite_in, + const bytes& joiner_secret, + const bytes& psk_secret, + const bytes& context) + : suite(suite_in) + , joiner_secret(joiner_secret) + , epoch_secret( + make_epoch_secret(suite_in, joiner_secret, psk_secret, context)) + , sender_data_secret(suite.derive_secret(epoch_secret, "sender data")) + , encryption_secret(suite.derive_secret(epoch_secret, "encryption")) + , exporter_secret(suite.derive_secret(epoch_secret, "exporter")) + , epoch_authenticator(suite.derive_secret(epoch_secret, "authentication")) + , external_secret(suite.derive_secret(epoch_secret, "external")) + , confirmation_key(suite.derive_secret(epoch_secret, "confirm")) + , membership_key(suite.derive_secret(epoch_secret, "membership")) + , resumption_psk(suite.derive_secret(epoch_secret, "resumption")) + , init_secret(suite.derive_secret(epoch_secret, "init")) + , external_priv(HPKEPrivateKey::derive(suite, external_secret)) +{ +} + +KeyScheduleEpoch::KeyScheduleEpoch(CipherSuite suite_in) + : suite(suite_in) +{ +} + +KeyScheduleEpoch::KeyScheduleEpoch(CipherSuite suite_in, + const bytes& init_secret, + const bytes& context) + : KeyScheduleEpoch( + suite_in, + make_joiner_secret(suite_in, context, init_secret, suite_in.zero()), + { /* no PSKs */ }, + context) +{ +} + +KeyScheduleEpoch::KeyScheduleEpoch(CipherSuite suite_in, + const bytes& init_secret, + const bytes& commit_secret, + const bytes& psk_secret, + const bytes& context) + : KeyScheduleEpoch( + suite_in, + make_joiner_secret(suite_in, context, init_secret, commit_secret), + psk_secret, + context) +{ +} + +std::tuple +KeyScheduleEpoch::external_init(CipherSuite suite, + const HPKEPublicKey& external_pub) +{ + auto size = suite.secret_size(); + return external_pub.do_export( + suite, {}, "MLS 1.0 external init secret", size); +} + +bytes +KeyScheduleEpoch::receive_external_init(const bytes& kem_output) const +{ + auto size = suite.secret_size(); + return external_priv.do_export( + suite, {}, kem_output, "MLS 1.0 external init secret", size); +} + +KeyScheduleEpoch +KeyScheduleEpoch::next(const bytes& commit_secret, + const std::vector& psks, + const std::optional& force_init_secret, + const bytes& context) const +{ + return next_raw( + commit_secret, make_psk_secret(suite, psks), force_init_secret, context); +} + +KeyScheduleEpoch +KeyScheduleEpoch::next_raw(const bytes& commit_secret, + const bytes& psk_secret, + const std::optional& force_init_secret, + const bytes& context) const +{ + auto actual_init_secret = init_secret; + if (force_init_secret) { + actual_init_secret = opt::get(force_init_secret); + } + + return { suite, actual_init_secret, commit_secret, psk_secret, context }; +} + +GroupKeySource +KeyScheduleEpoch::encryption_keys(LeafCount size) const +{ + return { suite, size, encryption_secret }; +} + +bytes +KeyScheduleEpoch::confirmation_tag(const bytes& confirmed_transcript_hash) const +{ + return suite.digest().hmac(confirmation_key, confirmed_transcript_hash); +} + +bytes +KeyScheduleEpoch::do_export(const std::string& label, + const bytes& context, + size_t size) const +{ + auto secret = suite.derive_secret(exporter_secret, label); + auto context_hash = suite.digest().hash(context); + return suite.expand_with_label(secret, "exported", context_hash, size); +} + +PSKWithSecret +KeyScheduleEpoch::resumption_psk_w_secret(ResumptionPSKUsage usage, + const bytes& group_id, + epoch_t epoch) +{ + auto nonce = random_bytes(suite.secret_size()); + auto psk = ResumptionPSK{ usage, group_id, epoch }; + return { { psk, nonce }, resumption_psk }; +} + +bytes +KeyScheduleEpoch::make_psk_secret(CipherSuite suite, + const std::vector& psks) +{ + auto psk_secret = suite.zero(); + auto count = uint16_t(psks.size()); + auto index = uint16_t(0); + for (const auto& psk : psks) { + auto psk_extracted = suite.hpke().kdf.extract(suite.zero(), psk.secret); + auto psk_label = tls::marshal(PSKLabel{ psk.id, index, count }); + auto psk_input = suite.expand_with_label( + psk_extracted, "derived psk", psk_label, suite.secret_size()); + psk_secret = suite.hpke().kdf.extract(psk_input, psk_secret); + index += 1; + } + return psk_secret; +} + +bytes +KeyScheduleEpoch::welcome_secret(CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks) +{ + auto psk_secret = make_psk_secret(suite, psks); + return welcome_secret_raw(suite, joiner_secret, psk_secret); +} + +bytes +KeyScheduleEpoch::welcome_secret_raw(CipherSuite suite, + const bytes& joiner_secret, + const bytes& psk_secret) +{ + auto extract = suite.hpke().kdf.extract(joiner_secret, psk_secret); + return suite.derive_secret(extract, "welcome"); +} + +KeyAndNonce +KeyScheduleEpoch::sender_data_keys(CipherSuite suite, + const bytes& sender_data_secret, + const bytes& ciphertext) +{ + auto sample_size = suite.secret_size(); + auto sample = bytes(sample_size); + if (ciphertext.size() <= sample_size) { + sample = ciphertext; + } else { + sample = ciphertext.slice(0, sample_size); + } + + auto key_size = suite.hpke().aead.key_size; + auto nonce_size = suite.hpke().aead.nonce_size; + return { + suite.expand_with_label(sender_data_secret, "key", sample, key_size), + suite.expand_with_label(sender_data_secret, "nonce", sample, nonce_size), + }; +} + +bool +operator==(const KeyScheduleEpoch& lhs, const KeyScheduleEpoch& rhs) +{ + auto epoch_secret = (lhs.epoch_secret == rhs.epoch_secret); + auto sender_data_secret = (lhs.sender_data_secret == rhs.sender_data_secret); + auto encryption_secret = (lhs.encryption_secret == rhs.encryption_secret); + auto exporter_secret = (lhs.exporter_secret == rhs.exporter_secret); + auto confirmation_key = (lhs.confirmation_key == rhs.confirmation_key); + auto init_secret = (lhs.init_secret == rhs.init_secret); + auto external_priv = (lhs.external_priv == rhs.external_priv); + + return epoch_secret && sender_data_secret && encryption_secret && + exporter_secret && confirmation_key && init_secret && external_priv; +} + +// struct { +// WireFormat wire_format; +// GroupContent content; // with content.content_type == commit +// opaque signature; +// } ConfirmedTranscriptHashInput; +struct ConfirmedTranscriptHashInput +{ + WireFormat wire_format; + const GroupContent& content; + const bytes& signature; + + TLS_SERIALIZABLE(wire_format, content, signature) +}; + +// struct { +// MAC confirmation_tag; +// } InterimTranscriptHashInput; +struct InterimTranscriptHashInput +{ + bytes confirmation_tag; + + TLS_SERIALIZABLE(confirmation_tag) +}; + +TranscriptHash::TranscriptHash(CipherSuite suite_in) + : suite(suite_in) +{ +} + +TranscriptHash::TranscriptHash(CipherSuite suite_in, + bytes confirmed_in, + const bytes& confirmation_tag) + : suite(suite_in) + , confirmed(std::move(confirmed_in)) +{ + update_interim(confirmation_tag); +} + +void +TranscriptHash::update(const AuthenticatedContent& content_auth) +{ + update_confirmed(content_auth); + update_interim(content_auth); +} + +void +TranscriptHash::update_confirmed(const AuthenticatedContent& content_auth) +{ + const auto transcript = + interim + content_auth.confirmed_transcript_hash_input(); + confirmed = suite.digest().hash(transcript); +} + +void +TranscriptHash::update_interim(const bytes& confirmation_tag) +{ + const auto transcript = confirmed + tls::marshal(confirmation_tag); + interim = suite.digest().hash(transcript); +} + +void +TranscriptHash::update_interim(const AuthenticatedContent& content_auth) +{ + const auto transcript = + confirmed + content_auth.interim_transcript_hash_input(); + interim = suite.digest().hash(transcript); +} + +bool +operator==(const TranscriptHash& lhs, const TranscriptHash& rhs) +{ + auto confirmed = (lhs.confirmed == rhs.confirmed); + auto interim = (lhs.interim == rhs.interim); + return confirmed && interim; +} + +} // namespace mlspp diff --git a/mlspp/src/messages.cpp b/mlspp/src/messages.cpp new file mode 100755 index 0000000000..5372ea5236 --- /dev/null +++ b/mlspp/src/messages.cpp @@ -0,0 +1,947 @@ +#include +#include +#include +#include + +#include "grease.h" + +namespace mlspp { + +// Extensions + +const Extension::Type ExternalPubExtension::type = ExtensionType::external_pub; +const Extension::Type RatchetTreeExtension::type = ExtensionType::ratchet_tree; +const Extension::Type ExternalSendersExtension::type = + ExtensionType::external_senders; +const Extension::Type SFrameParameters::type = ExtensionType::sframe_parameters; +const Extension::Type SFrameCapabilities::type = + ExtensionType::sframe_parameters; + +bool +SFrameCapabilities::compatible(const SFrameParameters& params) const +{ + return stdx::contains(cipher_suites, params.cipher_suite); +} + +// GroupContext + +GroupContext::GroupContext(CipherSuite cipher_suite_in, + bytes group_id_in, + epoch_t epoch_in, + bytes tree_hash_in, + bytes confirmed_transcript_hash_in, + ExtensionList extensions_in) + : cipher_suite(cipher_suite_in) + , group_id(std::move(group_id_in)) + , epoch(epoch_in) + , tree_hash(std::move(tree_hash_in)) + , confirmed_transcript_hash(std::move(confirmed_transcript_hash_in)) + , extensions(std::move(extensions_in)) +{ +} + +// GroupInfo + +GroupInfo::GroupInfo(GroupContext group_context_in, + ExtensionList extensions_in, + bytes confirmation_tag_in) + : group_context(std::move(group_context_in)) + , extensions(std::move(extensions_in)) + , confirmation_tag(std::move(confirmation_tag_in)) + , signer(0) +{ + grease(extensions); +} + +struct GroupInfoTBS +{ + GroupContext group_context; + ExtensionList extensions; + bytes confirmation_tag; + LeafIndex signer; + + TLS_SERIALIZABLE(group_context, extensions, confirmation_tag, signer) +}; + +bytes +GroupInfo::to_be_signed() const +{ + return tls::marshal( + GroupInfoTBS{ group_context, extensions, confirmation_tag, signer }); +} + +void +GroupInfo::sign(const TreeKEMPublicKey& tree, + LeafIndex signer_index, + const SignaturePrivateKey& priv) +{ + auto maybe_leaf = tree.leaf_node(signer_index); + if (!maybe_leaf) { + throw InvalidParameterError("Cannot sign from a blank leaf"); + } + + if (priv.public_key != opt::get(maybe_leaf).signature_key) { + throw InvalidParameterError("Bad key for index"); + } + + signer = signer_index; + signature = priv.sign(tree.suite, sign_label::group_info, to_be_signed()); +} + +bool +GroupInfo::verify(const TreeKEMPublicKey& tree) const +{ + auto maybe_leaf = tree.leaf_node(signer); + if (!maybe_leaf) { + throw InvalidParameterError("Signer not found"); + } + + const auto& leaf = opt::get(maybe_leaf); + return verify(leaf.signature_key); +} + +void +GroupInfo::sign(LeafIndex signer_index, const SignaturePrivateKey& priv) +{ + signer = signer_index; + signature = priv.sign( + group_context.cipher_suite, sign_label::group_info, to_be_signed()); +} + +bool +GroupInfo::verify(const SignaturePublicKey& pub) const +{ + return pub.verify(group_context.cipher_suite, + sign_label::group_info, + to_be_signed(), + signature); +} + +// Welcome + +Welcome::Welcome() + : cipher_suite(CipherSuite::ID::unknown) +{ +} + +Welcome::Welcome(CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks, + const GroupInfo& group_info) + : cipher_suite(suite) + , _joiner_secret(joiner_secret) +{ + // Cache the list of PSK IDs + for (const auto& psk : psks) { + _psks.psks.push_back(psk.id); + } + + // Pre-encrypt the GroupInfo + auto [key, nonce] = group_info_key_nonce(suite, joiner_secret, psks); + auto group_info_data = tls::marshal(group_info); + encrypted_group_info = + cipher_suite.hpke().aead.seal(key, nonce, {}, group_info_data); +} + +std::optional +Welcome::find(const KeyPackage& kp) const +{ + auto ref = kp.ref(); + for (size_t i = 0; i < secrets.size(); i++) { + if (ref == secrets[i].new_member) { + return static_cast(i); + } + } + return std::nullopt; +} + +void +Welcome::encrypt(const KeyPackage& kp, const std::optional& path_secret) +{ + auto gs = GroupSecrets{ _joiner_secret, std::nullopt, _psks }; + if (path_secret) { + gs.path_secret = GroupSecrets::PathSecret{ opt::get(path_secret) }; + } + + auto gs_data = tls::marshal(gs); + auto enc_gs = kp.init_key.encrypt( + kp.cipher_suite, encrypt_label::welcome, encrypted_group_info, gs_data); + secrets.push_back({ kp.ref(), enc_gs }); +} + +GroupSecrets +Welcome::decrypt_secrets(int kp_index, const HPKEPrivateKey& init_priv) const +{ + auto secrets_data = + init_priv.decrypt(cipher_suite, + encrypt_label::welcome, + encrypted_group_info, + secrets.at(kp_index).encrypted_group_secrets); + return tls::get(secrets_data); +} + +GroupInfo +Welcome::decrypt(const bytes& joiner_secret, + const std::vector& psks) const +{ + auto [key, nonce] = group_info_key_nonce(cipher_suite, joiner_secret, psks); + auto group_info_data = + cipher_suite.hpke().aead.open(key, nonce, {}, encrypted_group_info); + if (!group_info_data) { + throw ProtocolError("Welcome decryption failed"); + } + + return tls::get(opt::get(group_info_data)); +} + +KeyAndNonce +Welcome::group_info_key_nonce(CipherSuite suite, + const bytes& joiner_secret, + const std::vector& psks) +{ + auto welcome_secret = + KeyScheduleEpoch::welcome_secret(suite, joiner_secret, psks); + + // XXX(RLB): These used to be done with ExpandWithLabel. Should we do that + // instead, for better domain separation? (In particular, including "mls10") + // That is what we do for the sender data key/nonce. + auto key = + suite.expand_with_label(welcome_secret, "key", {}, suite.key_size()); + auto nonce = + suite.expand_with_label(welcome_secret, "nonce", {}, suite.nonce_size()); + return { std::move(key), std::move(nonce) }; +} + +// Commit +std::optional +Commit::valid_external() const +{ + // External Commits MUST contain a path field (and is therefore a "full" + // Commit). The joiner is added at the leftmost free leaf node (just as if + // they were added with an Add proposal), and the path is calculated relative + // to that leaf node. + // + // The Commit MUST NOT include any proposals by reference, since an external + // joiner cannot determine the validity of proposals sent within the group + const auto all_by_value = stdx::all_of(proposals, [](const auto& p) { + return var::holds_alternative(p.content); + }); + if (!path || !all_by_value) { + return std::nullopt; + } + + const auto ext_init_ptr = stdx::find_if(proposals, [](const auto& p) { + const auto proposal = var::get(p.content); + return proposal.proposal_type() == ProposalType::external_init; + }); + if (ext_init_ptr == proposals.end()) { + return std::nullopt; + } + + const auto& ext_init_proposal = var::get(ext_init_ptr->content); + const auto& ext_init = var::get(ext_init_proposal.content); + return ext_init.kem_output; +} + +// PublicMessage +Proposal::Type +Proposal::proposal_type() const +{ + return tls::variant::type(content).val; +} + +SenderType +Sender::sender_type() const +{ + return tls::variant::type(sender); +} + +tls::ostream& +operator<<(tls::ostream& str, const GroupContentAuthData& obj) +{ + switch (obj.content_type) { + case ContentType::proposal: + case ContentType::application: + return str << obj.signature; + + case ContentType::commit: + return str << obj.signature << opt::get(obj.confirmation_tag); + + default: + throw InvalidParameterError("Invalid content type"); + } +} + +tls::istream& +operator>>(tls::istream& str, GroupContentAuthData& obj) +{ + switch (obj.content_type) { + case ContentType::proposal: + case ContentType::application: + return str >> obj.signature; + + case ContentType::commit: + obj.confirmation_tag.emplace(); + return str >> obj.signature >> opt::get(obj.confirmation_tag); + + default: + throw InvalidParameterError("Invalid content type"); + } +} + +bool +operator==(const GroupContentAuthData& lhs, const GroupContentAuthData& rhs) +{ + return lhs.content_type == rhs.content_type && + lhs.signature == rhs.signature && + lhs.confirmation_tag == rhs.confirmation_tag; +} + +GroupContent::GroupContent(bytes group_id_in, + epoch_t epoch_in, + Sender sender_in, + bytes authenticated_data_in, + RawContent content_in) + : group_id(std::move(group_id_in)) + , epoch(epoch_in) + , sender(sender_in) + , authenticated_data(std::move(authenticated_data_in)) + , content(std::move(content_in)) +{ +} + +GroupContent::GroupContent(bytes group_id_in, + epoch_t epoch_in, + Sender sender_in, + bytes authenticated_data_in, + ContentType content_type) + : group_id(std::move(group_id_in)) + , epoch(epoch_in) + , sender(sender_in) + , authenticated_data(std::move(authenticated_data_in)) +{ + switch (content_type) { + case ContentType::commit: + content.emplace(); + break; + + case ContentType::proposal: + content.emplace(); + break; + + case ContentType::application: + content.emplace(); + break; + + default: + throw InvalidParameterError("Invalid content type"); + } +} + +ContentType +GroupContent::content_type() const +{ + return tls::variant::type(content); +} + +AuthenticatedContent +AuthenticatedContent::sign(WireFormat wire_format, + GroupContent content, + CipherSuite suite, + const SignaturePrivateKey& sig_priv, + const std::optional& context) +{ + if (wire_format == WireFormat::mls_public_message && + content.content_type() == ContentType::application) { + throw InvalidParameterError( + "Application data cannot be sent as PublicMessage"); + } + + auto content_auth = AuthenticatedContent{ wire_format, std::move(content) }; + auto tbs = content_auth.to_be_signed(context); + content_auth.auth.signature = + sig_priv.sign(suite, sign_label::mls_content, tbs); + return content_auth; +} + +bool +AuthenticatedContent::verify(CipherSuite suite, + const SignaturePublicKey& sig_pub, + const std::optional& context) const +{ + if (wire_format == WireFormat::mls_public_message && + content.content_type() == ContentType::application) { + return false; + } + + auto tbs = to_be_signed(context); + return sig_pub.verify(suite, sign_label::mls_content, tbs, auth.signature); +} + +struct ConfirmedTranscriptHashInput +{ + WireFormat wire_format; + const GroupContent& content; + const bytes& signature; + + TLS_SERIALIZABLE(wire_format, content, signature); +}; + +struct InterimTranscriptHashInput +{ + const bytes& confirmation_tag; + + TLS_SERIALIZABLE(confirmation_tag); +}; + +bytes +AuthenticatedContent::confirmed_transcript_hash_input() const +{ + return tls::marshal(ConfirmedTranscriptHashInput{ + wire_format, + content, + auth.signature, + }); +} + +bytes +AuthenticatedContent::interim_transcript_hash_input() const +{ + return tls::marshal( + InterimTranscriptHashInput{ opt::get(auth.confirmation_tag) }); +} + +void +AuthenticatedContent::set_confirmation_tag(const bytes& confirmation_tag) +{ + auth.confirmation_tag = confirmation_tag; +} + +bool +AuthenticatedContent::check_confirmation_tag( + const bytes& confirmation_tag) const +{ + return confirmation_tag == opt::get(auth.confirmation_tag); +} + +tls::ostream& +operator<<(tls::ostream& str, const AuthenticatedContent& obj) +{ + return str << obj.wire_format << obj.content << obj.auth; +} + +tls::istream& +operator>>(tls::istream& str, AuthenticatedContent& obj) +{ + str >> obj.wire_format >> obj.content; + + obj.auth.content_type = obj.content.content_type(); + return str >> obj.auth; +} + +bool +operator==(const AuthenticatedContent& lhs, const AuthenticatedContent& rhs) +{ + return lhs.wire_format == rhs.wire_format && lhs.content == rhs.content && + lhs.auth == rhs.auth; +} + +AuthenticatedContent::AuthenticatedContent(WireFormat wire_format_in, + GroupContent content_in) + : wire_format(wire_format_in) + , content(std::move(content_in)) +{ + auth.content_type = content.content_type(); +} + +AuthenticatedContent::AuthenticatedContent(WireFormat wire_format_in, + GroupContent content_in, + GroupContentAuthData auth_in) + : wire_format(wire_format_in) + , content(std::move(content_in)) + , auth(std::move(auth_in)) +{ +} + +const AuthenticatedContent& +ValidatedContent::authenticated_content() const +{ + return content_auth; +} + +ValidatedContent::ValidatedContent(AuthenticatedContent content_auth_in) + : content_auth(std::move(content_auth_in)) +{ +} + +bool +operator==(const ValidatedContent& lhs, const ValidatedContent& rhs) +{ + return lhs.content_auth == rhs.content_auth; +} + +struct GroupContentTBS +{ + WireFormat wire_format = WireFormat::reserved; + const GroupContent& content; + const std::optional& context; +}; + +static tls::ostream& +operator<<(tls::ostream& str, const GroupContentTBS& obj) +{ + str << ProtocolVersion::mls10 << obj.wire_format << obj.content; + + switch (obj.content.sender.sender_type()) { + case SenderType::member: + case SenderType::new_member_commit: + str << opt::get(obj.context); + break; + + case SenderType::external: + case SenderType::new_member_proposal: + break; + + default: + throw InvalidParameterError("Invalid sender type"); + } + + return str; +} + +bytes +AuthenticatedContent::to_be_signed( + const std::optional& context) const +{ + return tls::marshal(GroupContentTBS{ + wire_format, + content, + context, + }); +} + +PublicMessage +PublicMessage::protect(AuthenticatedContent content_auth, + CipherSuite suite, + const std::optional& membership_key, + const std::optional& context) +{ + auto pt = PublicMessage(std::move(content_auth)); + + // Add the membership_mac if required + switch (pt.content.sender.sender_type()) { + case SenderType::member: + pt.membership_tag = + pt.membership_mac(suite, opt::get(membership_key), context); + break; + + default: + break; + } + + return pt; +} + +std::optional +PublicMessage::unprotect(CipherSuite suite, + const std::optional& membership_key, + const std::optional& context) const +{ + // Verify the membership_tag if the message was sent within the group + switch (content.sender.sender_type()) { + case SenderType::member: { + auto candidate = membership_mac(suite, opt::get(membership_key), context); + if (candidate != opt::get(membership_tag)) { + return std::nullopt; + } + break; + } + + default: + break; + } + + return { { AuthenticatedContent{ + WireFormat::mls_public_message, + content, + auth, + } } }; +} + +bool +PublicMessage::contains(const AuthenticatedContent& content_auth) const +{ + return content == content_auth.content && auth == content_auth.auth; +} + +AuthenticatedContent +PublicMessage::authenticated_content() const +{ + auto auth_content = AuthenticatedContent{}; + auth_content.wire_format = WireFormat::mls_public_message; + auth_content.content = content; + auth_content.auth = auth; + return auth_content; +} + +PublicMessage::PublicMessage(AuthenticatedContent content_auth) + : content(std::move(content_auth.content)) + , auth(std::move(content_auth.auth)) +{ + if (content_auth.wire_format != WireFormat::mls_public_message) { + throw InvalidParameterError("Wire format mismatch (not mls_plaintext)"); + } +} + +struct GroupContentTBM +{ + GroupContentTBS content_tbs; + GroupContentAuthData auth; + + TLS_SERIALIZABLE(content_tbs, auth); +}; + +bytes +PublicMessage::membership_mac(CipherSuite suite, + const bytes& membership_key, + const std::optional& context) const +{ + auto tbm = tls::marshal(GroupContentTBM{ + { WireFormat::mls_public_message, content, context }, + auth, + }); + + return suite.digest().hmac(membership_key, tbm); +} + +tls::ostream& +operator<<(tls::ostream& str, const PublicMessage& obj) +{ + switch (obj.content.sender.sender_type()) { + case SenderType::member: + return str << obj.content << obj.auth << opt::get(obj.membership_tag); + + case SenderType::external: + case SenderType::new_member_proposal: + case SenderType::new_member_commit: + return str << obj.content << obj.auth; + + default: + throw InvalidParameterError("Invalid sender type"); + } +} + +tls::istream& +operator>>(tls::istream& str, PublicMessage& obj) +{ + str >> obj.content; + + obj.auth.content_type = obj.content.content_type(); + str >> obj.auth; + + if (obj.content.sender.sender_type() == SenderType::member) { + obj.membership_tag.emplace(); + str >> opt::get(obj.membership_tag); + } + + return str; +} + +bool +operator==(const PublicMessage& lhs, const PublicMessage& rhs) +{ + return lhs.content == rhs.content && lhs.auth == rhs.auth && + lhs.membership_tag == rhs.membership_tag; +} + +bool +operator!=(const PublicMessage& lhs, const PublicMessage& rhs) +{ + return !(lhs == rhs); +} + +static bytes +marshal_ciphertext_content(const GroupContent& content, + const GroupContentAuthData& auth, + size_t padding_size) +{ + auto w = tls::ostream{}; + var::visit([&w](const auto& val) { w << val; }, content.content); + w << auth; + w.write_raw(bytes(padding_size, 0)); + return w.bytes(); +} + +static void +unmarshal_ciphertext_content(const bytes& content_pt, + GroupContent& content, + GroupContentAuthData& auth) +{ + auto r = tls::istream(content_pt); + + var::visit([&r](auto& val) { r >> val; }, content.content); + r >> auth; + + const auto padding = r.bytes(); + const auto nonzero = [](const auto& x) { return x != 0; }; + if (stdx::any_of(padding, nonzero)) { + throw ProtocolError("Malformed AuthenticatedContentTBE padding"); + } +} + +struct ContentAAD +{ + const bytes& group_id; + const epoch_t epoch; + const ContentType content_type; + const bytes& authenticated_data; + + TLS_SERIALIZABLE(group_id, epoch, content_type, authenticated_data) +}; + +struct SenderData +{ + LeafIndex sender{ 0 }; + uint32_t generation{ 0 }; + ReuseGuard reuse_guard{ 0, 0, 0, 0 }; + + TLS_SERIALIZABLE(sender, generation, reuse_guard) +}; + +struct SenderDataAAD +{ + const bytes& group_id; + const epoch_t epoch; + const ContentType content_type; + + TLS_SERIALIZABLE(group_id, epoch, content_type) +}; + +PrivateMessage +PrivateMessage::protect(AuthenticatedContent content_auth, + CipherSuite suite, + GroupKeySource& keys, + const bytes& sender_data_secret, + size_t padding_size) +{ + // Pull keys from the secret tree + auto index = + var::get(content_auth.content.sender.sender).sender; + auto content_type = content_auth.content.content_type(); + auto [generation, reuse_guard, content_keys] = keys.next(content_type, index); + + // Encrypt the content + auto content_pt = marshal_ciphertext_content( + content_auth.content, content_auth.auth, padding_size); + auto content_aad = tls::marshal(ContentAAD{ + content_auth.content.group_id, + content_auth.content.epoch, + content_auth.content.content_type(), + content_auth.content.authenticated_data, + }); + + auto content_ct = suite.hpke().aead.seal( + content_keys.key, content_keys.nonce, content_aad, content_pt); + + // Encrypt the sender data + auto sender_index = + var::get(content_auth.content.sender.sender).sender; + auto sender_data_pt = tls::marshal(SenderData{ + sender_index, + generation, + reuse_guard, + }); + auto sender_data_aad = tls::marshal(SenderDataAAD{ + content_auth.content.group_id, + content_auth.content.epoch, + content_auth.content.content_type(), + }); + + auto sender_data_keys = + KeyScheduleEpoch::sender_data_keys(suite, sender_data_secret, content_ct); + + auto sender_data_ct = suite.hpke().aead.seal(sender_data_keys.key, + sender_data_keys.nonce, + sender_data_aad, + sender_data_pt); + + return PrivateMessage{ + std::move(content_auth.content), + std::move(sender_data_ct), + std::move(content_ct), + }; +} + +std::optional +PrivateMessage::unprotect(CipherSuite suite, + GroupKeySource& keys, + const bytes& sender_data_secret) const +{ + // Decrypt and parse the sender data + auto sender_data_keys = + KeyScheduleEpoch::sender_data_keys(suite, sender_data_secret, ciphertext); + auto sender_data_aad = tls::marshal(SenderDataAAD{ + group_id, + epoch, + content_type, + }); + + auto sender_data_pt = suite.hpke().aead.open(sender_data_keys.key, + sender_data_keys.nonce, + sender_data_aad, + encrypted_sender_data); + if (!sender_data_pt) { + return std::nullopt; + } + + auto sender_data = tls::get(opt::get(sender_data_pt)); + if (!keys.has_leaf(sender_data.sender)) { + return std::nullopt; + } + + // Decrypt the content + auto content_keys = keys.get(content_type, + sender_data.sender, + sender_data.generation, + sender_data.reuse_guard); + keys.erase(content_type, sender_data.sender, sender_data.generation); + + auto content_aad = tls::marshal(ContentAAD{ + group_id, + epoch, + content_type, + authenticated_data, + }); + + auto content_pt = suite.hpke().aead.open( + content_keys.key, content_keys.nonce, content_aad, ciphertext); + if (!content_pt) { + return std::nullopt; + } + + // Parse the content + auto content = GroupContent{ group_id, + epoch, + { MemberSender{ sender_data.sender } }, + authenticated_data, + content_type }; + auto auth = GroupContentAuthData{ content_type, {}, {} }; + + unmarshal_ciphertext_content(opt::get(content_pt), content, auth); + + return { { AuthenticatedContent{ + WireFormat::mls_private_message, + std::move(content), + std::move(auth), + } } }; +} + +PrivateMessage::PrivateMessage(GroupContent content, + bytes encrypted_sender_data_in, + bytes ciphertext_in) + : group_id(std::move(content.group_id)) + , epoch(content.epoch) + , content_type(content.content_type()) + , authenticated_data(std::move(content.authenticated_data)) + , encrypted_sender_data(std::move(encrypted_sender_data_in)) + , ciphertext(std::move(ciphertext_in)) +{ +} + +bytes +MLSMessage::group_id() const +{ + return var::visit( + overloaded{ + [](const PublicMessage& pt) -> bytes { return pt.get_group_id(); }, + [](const PrivateMessage& ct) -> bytes { return ct.get_group_id(); }, + [](const GroupInfo& gi) -> bytes { return gi.group_context.group_id; }, + [](const auto& /* unused */) -> bytes { + throw InvalidParameterError("MLSMessage has no group_id"); + }, + }, + message); +} + +epoch_t +MLSMessage::epoch() const +{ + return var::visit( + overloaded{ + [](const PublicMessage& pt) -> epoch_t { return pt.get_epoch(); }, + [](const PrivateMessage& pt) -> epoch_t { return pt.get_epoch(); }, + [](const auto& /* unused */) -> epoch_t { + throw InvalidParameterError("MLSMessage has no epoch"); + }, + }, + message); +} + +WireFormat +MLSMessage::wire_format() const +{ + return tls::variant::type(message); +} + +MLSMessage::MLSMessage(PublicMessage public_message) + : message(std::move(public_message)) +{ +} + +MLSMessage::MLSMessage(PrivateMessage private_message) + : message(std::move(private_message)) +{ +} + +MLSMessage::MLSMessage(Welcome welcome) + : message(std::move(welcome)) +{ +} + +MLSMessage::MLSMessage(GroupInfo group_info) + : message(std::move(group_info)) +{ +} + +MLSMessage::MLSMessage(KeyPackage key_package) + : message(std::move(key_package)) +{ +} + +MLSMessage +external_proposal(CipherSuite suite, + const bytes& group_id, + epoch_t epoch, + const Proposal& proposal, + uint32_t signer_index, + const SignaturePrivateKey& sig_priv) +{ + switch (proposal.proposal_type()) { + // These proposal types are OK + case ProposalType::add: + case ProposalType::remove: + case ProposalType::psk: + case ProposalType::reinit: + case ProposalType::group_context_extensions: + break; + + // These proposal types are forbidden + case ProposalType::invalid: + case ProposalType::update: + case ProposalType::external_init: + default: + throw ProtocolError("External proposal has invalid type"); + } + + auto content = GroupContent{ group_id, + epoch, + { ExternalSenderIndex{ signer_index } }, + { /* no authenticated data */ }, + { proposal } }; + auto content_auth = AuthenticatedContent::sign( + WireFormat::mls_public_message, std::move(content), suite, sig_priv, {}); + + return PublicMessage::protect(std::move(content_auth), suite, {}, {}); +} + +} // namespace mlspp diff --git a/mlspp/src/session.cpp b/mlspp/src/session.cpp new file mode 100755 index 0000000000..f96b6bba63 --- /dev/null +++ b/mlspp/src/session.cpp @@ -0,0 +1,437 @@ +#include +#include + +#include + +namespace mlspp { + +/// +/// Inner struct declarations for PendingJoin and Session +/// + +struct PendingJoin::Inner +{ + const CipherSuite suite; + const HPKEPrivateKey init_priv; + const HPKEPrivateKey leaf_priv; + const SignaturePrivateKey sig_priv; + const KeyPackage key_package; + + Inner(CipherSuite suite_in, + SignaturePrivateKey sig_priv_in, + Credential cred_in); + + static PendingJoin create(CipherSuite suite, + SignaturePrivateKey sig_priv, + Credential cred); +}; + +struct Session::Inner +{ + std::deque history; + std::map outbound_cache; + bool encrypt_handshake{ false }; + + explicit Inner(State state); + + static Session begin(CipherSuite suite, + const bytes& group_id, + const HPKEPrivateKey& leaf_priv, + const SignaturePrivateKey& sig_priv, + const LeafNode& leaf_node); + static Session join(const HPKEPrivateKey& init_priv, + const HPKEPrivateKey& leaf_priv, + const SignaturePrivateKey& sig_priv, + const KeyPackage& key_package, + const bytes& welcome_data); + + bytes fresh_secret() const; + MLSMessage import_handshake(const bytes& encoded) const; + State& for_epoch(epoch_t epoch); +}; + +/// +/// Client +/// + +Client::Client(CipherSuite suite_in, + SignaturePrivateKey sig_priv_in, + Credential cred_in) + : suite(suite_in) + , sig_priv(std::move(sig_priv_in)) + , cred(std::move(cred_in)) +{ +} + +Session +Client::begin_session(const bytes& group_id) const +{ + auto leaf_priv = HPKEPrivateKey::generate(suite); + auto leaf_node = LeafNode(suite, + leaf_priv.public_key, + sig_priv.public_key, + cred, + Capabilities::create_default(), + Lifetime::create_default(), + {}, + sig_priv); + + return Session::Inner::begin(suite, group_id, leaf_priv, sig_priv, leaf_node); +} + +PendingJoin +Client::start_join() const +{ + return PendingJoin::Inner::create(suite, sig_priv, cred); +} + +/// +/// PendingJoin +/// + +PendingJoin::Inner::Inner(CipherSuite suite_in, + SignaturePrivateKey sig_priv_in, + Credential cred_in) + : suite(suite_in) + , init_priv(HPKEPrivateKey::generate(suite)) + , leaf_priv(HPKEPrivateKey::generate(suite)) + , sig_priv(std::move(sig_priv_in)) + , key_package(suite, + init_priv.public_key, + LeafNode(suite, + leaf_priv.public_key, + sig_priv.public_key, + std::move(cred_in), + Capabilities::create_default(), + Lifetime::create_default(), + {}, + sig_priv), + {}, + sig_priv) +{ +} + +PendingJoin +PendingJoin::Inner::create(CipherSuite suite, + SignaturePrivateKey sig_priv, + Credential cred) +{ + auto inner = + std::make_unique(suite, std::move(sig_priv), std::move(cred)); + return { inner.release() }; +} + +PendingJoin::PendingJoin(PendingJoin&& other) noexcept = default; + +PendingJoin& +PendingJoin::operator=(PendingJoin&& other) noexcept = default; + +PendingJoin::~PendingJoin() = default; + +PendingJoin::PendingJoin(Inner* inner_in) + : inner(inner_in) +{ +} + +bytes +PendingJoin::key_package() const +{ + return tls::marshal(inner->key_package); +} + +Session +PendingJoin::complete(const bytes& welcome) const +{ + return Session::Inner::join(inner->init_priv, + inner->leaf_priv, + inner->sig_priv, + inner->key_package, + welcome); +} + +/// +/// Session +/// + +Session::Inner::Inner(State state) + : history{ std::move(state) } + , encrypt_handshake(true) +{ +} + +Session +Session::Inner::begin(CipherSuite suite, + const bytes& group_id, + const HPKEPrivateKey& leaf_priv, + const SignaturePrivateKey& sig_priv, + const LeafNode& leaf_node) +{ + auto state = State(group_id, suite, leaf_priv, sig_priv, leaf_node, {}); + auto inner = std::make_unique(state); + return { inner.release() }; +} + +Session +Session::Inner::join(const HPKEPrivateKey& init_priv, + const HPKEPrivateKey& leaf_priv, + const SignaturePrivateKey& sig_priv, + const KeyPackage& key_package, + const bytes& welcome_data) +{ + auto welcome = tls::get(welcome_data); + + auto state = State( + init_priv, leaf_priv, sig_priv, key_package, welcome, std::nullopt, {}); + auto inner = std::make_unique(state); + return { inner.release() }; +} + +bytes +Session::Inner::fresh_secret() const +{ + const auto suite = history.front().cipher_suite(); + return random_bytes(suite.secret_size()); +} + +MLSMessage +Session::Inner::import_handshake(const bytes& encoded) const +{ + auto msg = tls::get(encoded); + + switch (msg.wire_format()) { + case WireFormat::mls_public_message: + if (encrypt_handshake) { + throw ProtocolError("Handshake not encrypted as required"); + } + + return msg; + + case WireFormat::mls_private_message: { + if (!encrypt_handshake) { + throw ProtocolError("Unexpected handshake encryption"); + } + + return msg; + } + + default: + throw InvalidParameterError("Illegal wire format"); + } +} + +State& +Session::Inner::for_epoch(epoch_t epoch) +{ + for (auto& state : history) { + if (state.epoch() == epoch) { + return state; + } + } + + throw MissingStateError("No state for epoch"); +} + +Session::Session(Session&& other) noexcept = default; + +Session& +Session::operator=(Session&& other) noexcept = default; + +Session::~Session() = default; + +Session::Session(Inner* inner_in) + : inner(inner_in) +{ +} + +void +Session::encrypt_handshake(bool enabled) +{ + inner->encrypt_handshake = enabled; +} + +bytes +Session::add(const bytes& key_package_data) +{ + auto key_package = tls::get(key_package_data); + auto proposal = inner->history.front().add( + key_package, { inner->encrypt_handshake, {}, 0 }); + return tls::marshal(proposal); +} + +bytes +Session::update() +{ + auto leaf_secret = inner->fresh_secret(); + + auto leaf_priv = HPKEPrivateKey::generate(cipher_suite()); + auto proposal = inner->history.front().update( + std::move(leaf_priv), {}, { inner->encrypt_handshake, {}, 0 }); + return tls::marshal(proposal); +} + +bytes +Session::remove(uint32_t index) +{ + auto proposal = inner->history.front().remove( + RosterIndex{ index }, { inner->encrypt_handshake, {}, 0 }); + return tls::marshal(proposal); +} + +std::tuple +Session::commit(const bytes& proposal) +{ + return commit(std::vector{ proposal }); +} + +std::tuple +Session::commit(const std::vector& proposals) +{ + auto provisional_state = inner->history.front(); + for (const auto& proposal_data : proposals) { + auto msg = inner->import_handshake(proposal_data); + auto maybe_state = provisional_state.handle(msg); + if (maybe_state) { + throw InvalidParameterError("Invalid proposal; actually a commit"); + } + } + + inner->history.front() = std::move(provisional_state); + return commit(); +} + +std::tuple +Session::commit() +{ + auto commit_secret = inner->fresh_secret(); + auto encrypt = inner->encrypt_handshake; + auto [commit, welcome, new_state] = inner->history.front().commit( + commit_secret, CommitOpts{ {}, true, encrypt, {} }, { encrypt, {}, 0 }); + + auto commit_msg = tls::marshal(commit); + auto welcome_msg = tls::marshal(welcome); + + inner->outbound_cache.insert({ commit_msg, new_state }); + return std::make_tuple(welcome_msg, commit_msg); +} + +bool +Session::handle(const bytes& handshake_data) +{ + auto msg = inner->import_handshake(handshake_data); + + auto maybe_cached_state = std::optional{}; + auto node = inner->outbound_cache.extract(handshake_data); + if (!node.empty()) { + maybe_cached_state = node.mapped(); + } + + auto maybe_next_state = + inner->history.front().handle(msg, maybe_cached_state); + if (!maybe_next_state) { + return false; + } + + inner->history.emplace_front(opt::get(maybe_next_state)); + return true; +} + +epoch_t +Session::epoch() const +{ + return inner->history.front().epoch(); +} + +LeafIndex +Session::index() const +{ + return inner->history.front().index(); +} + +CipherSuite +Session::cipher_suite() const +{ + return inner->history.front().cipher_suite(); +} + +const ExtensionList& +Session::extensions() const +{ + return inner->history.front().extensions(); +} + +const TreeKEMPublicKey& +Session::tree() const +{ + return inner->history.front().tree(); +} + +bytes +Session::do_export(const std::string& label, + const bytes& context, + size_t size) const +{ + return inner->history.front().do_export(label, context, size); +} + +GroupInfo +Session::group_info() const +{ + return inner->history.front().group_info(true); +} + +std::vector +Session::roster() const +{ + return inner->history.front().roster(); +} + +bytes +Session::epoch_authenticator() const +{ + return inner->history.front().epoch_authenticator(); +} + +bytes +Session::protect(const bytes& plaintext) +{ + auto msg = inner->history.front().protect({}, plaintext, 0); + return tls::marshal(msg); +} + +// TODO(rlb@ipv.sx): It would be good to expose identity information +// here, since ciphertexts are authenticated per sender. Who sent +// this ciphertext? +bytes +Session::unprotect(const bytes& ciphertext) +{ + auto ciphertext_obj = tls::get(ciphertext); + auto& state = inner->for_epoch(ciphertext_obj.epoch()); + auto [aad, pt] = state.unprotect(ciphertext_obj); + silence_unused(aad); + return pt; +} + +bool +operator==(const Session& lhs, const Session& rhs) +{ + if (lhs.inner->encrypt_handshake != rhs.inner->encrypt_handshake) { + return false; + } + + auto size = std::min(lhs.inner->history.size(), rhs.inner->history.size()); + for (size_t i = 0; i < size; i += 1) { + if (lhs.inner->history.at(i) != rhs.inner->history.at(i)) { + return false; + } + } + + return true; +} + +bool +operator!=(const Session& lhs, const Session& rhs) +{ + return !(lhs == rhs); +} + +} // namespace mlspp diff --git a/mlspp/src/state.cpp b/mlspp/src/state.cpp new file mode 100755 index 0000000000..ed15c1e9eb --- /dev/null +++ b/mlspp/src/state.cpp @@ -0,0 +1,2219 @@ +#include +#include + +namespace mlspp { + +/// +/// Constructors +/// + +State::State(bytes group_id, + CipherSuite suite, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + ExtensionList extensions) + : _suite(suite) + , _group_id(std::move(group_id)) + , _epoch(0) + , _tree(suite) + , _transcript_hash(suite) + , _extensions(std::move(extensions)) + , _index(0) + , _identity_priv(std::move(sig_priv)) +{ + // Verify that the client supports the proposed group extensions + if (!leaf_node.verify_extension_support(_extensions)) { + throw InvalidParameterError("Client doesn't support required extensions"); + } + + _index = _tree.add_leaf(leaf_node); + _tree.set_hash_all(); + _tree_priv = TreeKEMPrivateKey::solo(suite, _index, std::move(enc_priv)); + if (!_tree_priv.consistent(_tree)) { + throw InvalidParameterError("LeafNode inconsistent with private key"); + } + + // XXX(RLB): Convert KeyScheduleEpoch to take GroupContext? + auto ctx = tls::marshal(group_context()); + _key_schedule = + KeyScheduleEpoch(_suite, random_bytes(_suite.secret_size()), ctx); + _keys = _key_schedule.encryption_keys(_tree.size); + + // Update the interim transcript hash with a virtual confirmation tag + _transcript_hash.update_interim( + _key_schedule.confirmation_tag(_transcript_hash.confirmed)); +} + +TreeKEMPublicKey +State::import_tree(const bytes& tree_hash, + const std::optional& external, + const ExtensionList& extensions) +{ + auto tree = TreeKEMPublicKey(_suite); + auto maybe_tree_extn = extensions.find(); + if (external) { + tree = opt::get(external); + } else if (maybe_tree_extn) { + tree = opt::get(maybe_tree_extn).tree; + } else { + throw InvalidParameterError("No tree available"); + } + + tree.suite = _suite; + + tree.set_hash_all(); + if (tree.root_hash() != tree_hash) { + throw InvalidParameterError("Tree does not match GroupInfo"); + } + + return tree; +} + +bool +State::validate_tree() const +{ + // The functionality here is somewhat duplicative of State::valid(const + // LeafNode&). Simply calling that method, however, would result in this + // method having quadratic scaling, since each call to valid() does a linear + // scan through the tree to check uniqueness of keys and compatibility of + // credential support. + + // Validate that the tree is parent-hash valid + if (!_tree.parent_hash_valid()) { + return false; + } + + // Validate the signatures on all leaves + const auto signature_valid = + _tree.all_leaves([&](auto i, const auto& leaf_node) { + auto binding = std::optional{}; + switch (leaf_node.source()) { + case LeafNodeSource::commit: + case LeafNodeSource::update: + binding = LeafNode::MemberBinding{ _group_id, i }; + break; + + default: + // Nothing to do + break; + } + + return leaf_node.verify(_suite, binding); + }); + if (!signature_valid) { + return false; + } + + // Collect cross-tree properties + auto n_leaves = size_t(0); + auto encryption_keys = std::set{}; + auto signature_keys = std::set{}; + auto credential_types = std::set{}; + _tree.all_leaves([&](auto /* i */, const auto& leaf_node) { + n_leaves += 1; + encryption_keys.insert(leaf_node.encryption_key.data); + signature_keys.insert(leaf_node.signature_key.data); + credential_types.insert(leaf_node.credential.type()); + return true; + }); + + // Verify uniqueness of keys + if (encryption_keys.size() != n_leaves) { + return false; + } + + if (signature_keys.size() != n_leaves) { + return false; + } + + // Verify that each leaf indicates support for all required parameters + return _tree.all_leaves([&](auto /* i */, const auto& leaf_node) { + const auto supports_group_extensions = + leaf_node.verify_extension_support(_extensions); + const auto supports_own_extensions = + leaf_node.verify_extension_support(leaf_node.extensions); + const auto supports_group_credentials = + leaf_node.capabilities.credentials_supported(credential_types); + return supports_group_extensions && supports_own_extensions && + supports_group_credentials; + }); +} + +State::State(SignaturePrivateKey sig_priv, + const GroupInfo& group_info, + const std::optional& tree) + : _suite(group_info.group_context.cipher_suite) + , _group_id(group_info.group_context.group_id) + , _epoch(group_info.group_context.epoch) + , _tree(import_tree(group_info.group_context.tree_hash, + tree, + group_info.extensions)) + , _transcript_hash(_suite, + group_info.group_context.confirmed_transcript_hash, + group_info.confirmation_tag) + , _extensions(group_info.group_context.extensions) + , _key_schedule(_suite) + , _index(0) + , _identity_priv(std::move(sig_priv)) +{ + if (!validate_tree()) { + throw InvalidParameterError("Invalid tree"); + } + + // The following are not set: + // _index + // _tree_priv + // + // This ctor should only be used within external_commit, in which case these + // fields are populated by the subsequent commit() +} + +// Initialize a group from a Welcome +State::State(const HPKEPrivateKey& init_priv, + HPKEPrivateKey leaf_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree, + std::map external_psks) + : State(init_priv, + std::move(leaf_priv), + std::move(sig_priv), + key_package, + welcome, + tree, + std::move(external_psks), + {}) +{ +} + +State::State(const HPKEPrivateKey& init_priv, + HPKEPrivateKey leaf_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree, + std::map external_psks, + std::map resumption_psks) + : _suite(welcome.cipher_suite) + , _epoch(0) + , _tree(welcome.cipher_suite) + , _transcript_hash(welcome.cipher_suite) + , _identity_priv(std::move(sig_priv)) + , _external_psks(std::move(external_psks)) + , _resumption_psks(std::move(resumption_psks)) +{ + auto maybe_kpi = welcome.find(key_package); + if (!maybe_kpi) { + throw InvalidParameterError("Welcome not intended for key package"); + } + auto kpi = opt::get(maybe_kpi); + + if (key_package.cipher_suite != welcome.cipher_suite) { + throw InvalidParameterError("Ciphersuite mismatch"); + } + + // Decrypt the GroupSecrets and look up required PSKs + auto secrets = welcome.decrypt_secrets(kpi, init_priv); + auto psks = resolve(secrets.psks.psks); + + // Decrypt the GroupInfo + auto group_info = welcome.decrypt(secrets.joiner_secret, psks); + if (group_info.group_context.cipher_suite != _suite) { + throw InvalidParameterError("GroupInfo and Welcome ciphersuites disagree"); + } + + // Import the tree from the argument or from the extension + _tree = import_tree( + group_info.group_context.tree_hash, tree, group_info.extensions); + + // Verify the signature on the GroupInfo + if (!group_info.verify(_tree)) { + throw InvalidParameterError("Invalid GroupInfo"); + } + + // Ingest the GroupSecrets and GroupInfo + _epoch = group_info.group_context.epoch; + _group_id = group_info.group_context.group_id; + + _transcript_hash.confirmed = + group_info.group_context.confirmed_transcript_hash; + _transcript_hash.update_interim(group_info.confirmation_tag); + + _extensions = group_info.group_context.extensions; + + // Validate that the tree is in fact consistent with the group's parameters + if (!validate_tree()) { + throw InvalidParameterError("Invalid tree"); + } + + // Construct TreeKEM private key from parts provided + auto maybe_index = _tree.find(key_package.leaf_node); + if (!maybe_index) { + throw InvalidParameterError("New joiner not in tree"); + } + + _index = opt::get(maybe_index); + + auto ancestor = _index.ancestor(group_info.signer); + auto path_secret = std::optional{}; + if (secrets.path_secret) { + path_secret = opt::get(secrets.path_secret).secret; + } + + _tree_priv = TreeKEMPrivateKey::joiner( + _tree, _index, std::move(leaf_priv), ancestor, path_secret); + + // Ratchet forward into the current epoch + auto group_ctx = tls::marshal(group_context()); + _key_schedule = + KeyScheduleEpoch::joiner(_suite, secrets.joiner_secret, psks, group_ctx); + _keys = _key_schedule.encryption_keys(_tree.size); + + // Verify the confirmation + const auto confirmation_tag = + _key_schedule.confirmation_tag(_transcript_hash.confirmed); + if (confirmation_tag != group_info.confirmation_tag) { + throw ProtocolError("Confirmation failed to verify"); + } +} + +std::tuple +State::external_join(const bytes& leaf_secret, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const GroupInfo& group_info, + const std::optional& tree, + const MessageOpts& msg_opts, + std::optional remove_prior, + const std::map& psks) +{ + // Create a preliminary state + auto initial_state = State(std::move(sig_priv), group_info, tree); + + // Look up the external public key for the group + const auto maybe_external_pub = + group_info.extensions.find(); + if (!maybe_external_pub) { + throw InvalidParameterError("No external pub in GroupInfo"); + } + + const auto& external_pub = opt::get(maybe_external_pub).external_pub; + + // Insert an ExternalInit proposal + auto opts = CommitOpts{}; + auto [enc, force_init_secret] = + KeyScheduleEpoch::external_init(key_package.cipher_suite, external_pub); + auto ext_init = Proposal{ ExternalInit{ enc } }; + opts.extra_proposals.push_back(ext_init); + + // Evict a prior appearance if required + if (remove_prior) { + auto remove = initial_state.remove_proposal(opt::get(remove_prior)); + opts.extra_proposals.push_back(remove); + } + + // Inject PSKs + for (const auto& [id, secret] : psks) { + initial_state.add_external_psk(id, secret); + auto psk = initial_state.pre_shared_key_proposal(id); + opts.extra_proposals.push_back(psk); + } + + // Use the preliminary state to create a commit and advance to a real state + auto params = ExternalCommitParams{ key_package, force_init_secret }; + auto [commit_msg, welcome, state] = + initial_state.commit(leaf_secret, opts, msg_opts, params); + silence_unused(welcome); + return { commit_msg, state }; +} + +MLSMessage +State::new_member_add(const bytes& group_id, + epoch_t epoch, + const KeyPackage& new_member, + const SignaturePrivateKey& sig_priv) +{ + const auto suite = new_member.cipher_suite; + auto proposal = Proposal{ Add{ new_member } }; + auto content = GroupContent{ group_id, + epoch, + { NewMemberProposalSender{} }, + { /* no authenticated data */ }, + { std::move(proposal) } }; + auto content_auth = AuthenticatedContent::sign( + WireFormat::mls_public_message, std::move(content), suite, sig_priv, {}); + + return PublicMessage::protect(std::move(content_auth), suite, {}, {}); +} + +/// +/// Proposal and commit factories +/// +template +MLSMessage +State::protect_full(Inner&& inner_content, const MessageOpts& msg_opts) +{ + auto content_auth = sign({ MemberSender{ _index } }, + std::forward(inner_content), + msg_opts.authenticated_data, + msg_opts.encrypt); + return protect(std::move(content_auth), msg_opts.padding_size); +} + +template +AuthenticatedContent +State::sign(const Sender& sender, + Inner&& inner_content, + const bytes& authenticated_data, + bool encrypt) const +{ + auto content = GroupContent{ _group_id, + _epoch, + sender, + authenticated_data, + { std::forward(inner_content) } }; + + auto wire_format = (encrypt) ? WireFormat::mls_private_message + : WireFormat::mls_public_message; + + auto content_auth = AuthenticatedContent::sign( + wire_format, std::move(content), _suite, _identity_priv, group_context()); + + return content_auth; +} + +MLSMessage +State::protect(AuthenticatedContent&& content_auth, size_t padding_size) +{ + switch (content_auth.wire_format) { + case WireFormat::mls_public_message: + return PublicMessage::protect(std::move(content_auth), + _suite, + _key_schedule.membership_key, + group_context()); + + case WireFormat::mls_private_message: + return PrivateMessage::protect(std::move(content_auth), + _suite, + _keys, + _key_schedule.sender_data_secret, + padding_size); + + default: + throw InvalidParameterError("Malformed AuthenticatedContent"); + } +} + +ValidatedContent +State::unwrap(const MLSMessage& msg) +{ + if (msg.version != ProtocolVersion::mls10) { + throw InvalidParameterError("Unsupported version"); + } + + const auto unprotect = overloaded{ + [&](const PublicMessage& pt) -> ValidatedContent { + if (pt.get_group_id() != _group_id) { + throw ProtocolError("PublicMessage not for this group"); + } + + if (pt.get_epoch() != _epoch) { + throw ProtocolError("PublicMessage not for this epoch"); + } + + auto maybe_content_auth = + pt.unprotect(_suite, _key_schedule.membership_key, group_context()); + if (!maybe_content_auth) { + throw ProtocolError("Membership tag failed to verify"); + } + return opt::get(maybe_content_auth); + }, + + [&](const PrivateMessage& ct) -> ValidatedContent { + if (ct.get_group_id() != _group_id) { + throw ProtocolError("PrivateMessage not for this group"); + } + + if (ct.get_epoch() != _epoch) { + throw ProtocolError("PrivateMessage not for this epoch"); + } + + auto maybe_content_auth = + ct.unprotect(_suite, _keys, _key_schedule.sender_data_secret); + if (!maybe_content_auth) { + throw ProtocolError("PrivateMessage decryption failure"); + } + return opt::get(maybe_content_auth); + }, + + [](const auto& /* unused */) -> ValidatedContent { + throw ProtocolError("Invalid wire format"); + }, + }; + + auto val_content = var::visit(unprotect, msg.message); + if (!verify(val_content.content_auth)) { + throw InvalidParameterError("Message signature failed to verify"); + } + + return val_content; +} + +Proposal +State::add_proposal(const KeyPackage& key_package) const +{ + // Check that the key package is validly signed + if (!key_package.verify()) { + throw InvalidParameterError("Invalid signature on key package"); + } + + // Check that the group's basic properties are supported + auto now = seconds_since_epoch(); + if (!key_package.leaf_node.verify_expiry(now)) { + throw InvalidParameterError("Expired key package"); + } + + // Check that the group's extensions are supported + if (!key_package.leaf_node.verify_extension_support(_extensions)) { + throw InvalidParameterError( + "Key package does not support group's extensions"); + } + + return { Add{ key_package } }; +} + +Proposal +State::update_proposal(HPKEPrivateKey leaf_priv, const LeafNodeOptions& opts) +{ + if (_cached_update) { + throw ProtocolError("Only one update may be generated per epoch"); + } + + auto leaf = opt::get(_tree.leaf_node(_index)); + + auto new_leaf = leaf.for_update( + _suite, _group_id, _index, leaf_priv.public_key, opts, _identity_priv); + + auto update = Update{ new_leaf }; + _cached_update = CachedUpdate{ std::move(leaf_priv), update }; + return { update }; +} + +Proposal +State::remove_proposal(RosterIndex index) const +{ + return remove_proposal(leaf_for_roster_entry(index)); +} + +Proposal +State::remove_proposal(LeafIndex removed) const +{ + if (!_tree.has_leaf(removed)) { + throw InvalidParameterError("Remove on blank leaf"); + } + + return { Remove{ removed } }; +} + +Proposal +State::group_context_extensions_proposal(ExtensionList exts) const +{ + if (!extensions_supported(exts)) { + throw InvalidParameterError("Unsupported extensions"); + } + + return { GroupContextExtensions{ std::move(exts) } }; +} + +Proposal +State::pre_shared_key_proposal(const bytes& external_psk_id) const +{ + if (_external_psks.count(external_psk_id) == 0) { + throw InvalidParameterError("Unknown PSK"); + } + + auto psk_id = PreSharedKeyID{ + { ExternalPSK{ external_psk_id } }, + random_bytes(_suite.secret_size()), + }; + return { PreSharedKey{ psk_id } }; +} + +Proposal +State::pre_shared_key_proposal(const bytes& group_id, epoch_t epoch) const +{ + if (epoch != _epoch && _resumption_psks.count({ group_id, epoch }) == 0) { + throw InvalidParameterError("Unknown PSK"); + } + + auto psk_id = PreSharedKeyID{ + { ResumptionPSK{ ResumptionPSKUsage::application, group_id, epoch } }, + random_bytes(_suite.secret_size()), + }; + return { PreSharedKey{ psk_id } }; +} + +Proposal +State::reinit_proposal(bytes group_id, + ProtocolVersion version, + CipherSuite cipher_suite, + ExtensionList extensions) +{ + return { ReInit{ + std::move(group_id), version, cipher_suite, std::move(extensions) } }; +} + +MLSMessage +State::add(const KeyPackage& key_package, const MessageOpts& msg_opts) +{ + return protect_full(add_proposal(key_package), msg_opts); +} + +MLSMessage +State::update(HPKEPrivateKey leaf_priv, + const LeafNodeOptions& opts, + const MessageOpts& msg_opts) +{ + return protect_full(update_proposal(std::move(leaf_priv), opts), msg_opts); +} + +MLSMessage +State::remove(RosterIndex index, const MessageOpts& msg_opts) +{ + return protect_full(remove_proposal(index), msg_opts); +} + +MLSMessage +State::remove(LeafIndex removed, const MessageOpts& msg_opts) +{ + return protect_full(remove_proposal(removed), msg_opts); +} + +MLSMessage +State::group_context_extensions(ExtensionList exts, const MessageOpts& msg_opts) +{ + return protect_full(group_context_extensions_proposal(std::move(exts)), + msg_opts); +} + +MLSMessage +State::pre_shared_key(const bytes& external_psk_id, const MessageOpts& msg_opts) +{ + return protect_full(pre_shared_key_proposal(external_psk_id), msg_opts); +} + +MLSMessage +State::pre_shared_key(const bytes& group_id, + epoch_t epoch, + const MessageOpts& msg_opts) +{ + return protect_full(pre_shared_key_proposal(group_id, epoch), msg_opts); +} + +MLSMessage +State::reinit(bytes group_id, + ProtocolVersion version, + CipherSuite cipher_suite, + ExtensionList extensions, + const MessageOpts& msg_opts) +{ + return protect_full( + reinit_proposal( + std::move(group_id), version, cipher_suite, std::move(extensions)), + msg_opts); +} + +std::tuple +State::commit(const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts) +{ + return commit(leaf_secret, opts, msg_opts, NormalCommitParams{}); +} + +std::tuple +State::commit(const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts, + CommitParams params) +{ + // Construct a commit from cached proposals + // TODO(rlb) ignore some proposals: + // * Update after Update + // * Update after Remove + // * Remove after Remove + Commit commit; + auto joiners = std::vector{}; + for (const auto& cached : _pending_proposals) { + if (var::holds_alternative(cached.proposal.content)) { + const auto& add = var::get(cached.proposal.content); + joiners.push_back(add.key_package); + } + + commit.proposals.push_back({ cached.ref }); + } + + // Add the extra proposals to those we had cached + if (opts) { + const auto& extra_proposals = opt::get(opts).extra_proposals; + for (const auto& proposal : extra_proposals) { + if (var::holds_alternative(proposal.content)) { + const auto& add = var::get(proposal.content); + joiners.push_back(add.key_package); + } + + commit.proposals.push_back({ proposal }); + } + } + + // If this is an external commit, insert an ExternalInit proposal + auto external_commit = std::optional{}; + if (var::holds_alternative(params)) { + external_commit = var::get(params); + } + + auto force_init_secret = std::optional{}; + if (external_commit) { + force_init_secret = opt::get(external_commit).force_init_secret; + } + + // Apply proposals + State next = successor(); + + const auto proposals = must_resolve(commit.proposals, _index); + if (!valid(proposals, _index, params)) { + throw ProtocolError("Invalid proposal list"); + } + + const auto [joiner_locations, psks] = next.apply(proposals); + + if (external_commit) { + const auto& leaf_node = + opt::get(external_commit).joiner_key_package.leaf_node; + next._index = next._tree.add_leaf(leaf_node); + } + + // If this is an external commit, indicate it in the sender field + auto sender = Sender{ MemberSender{ _index } }; + if (external_commit) { + sender = Sender{ NewMemberCommitSender{} }; + } + + // KEM new entropy to the group and the new joiners + auto commit_secret = _suite.zero(); + auto path_secrets = + std::vector>(joiner_locations.size()); + auto force_path = opts && opt::get(opts).force_path; + if (force_path || path_required(proposals)) { + auto leaf_node_opts = LeafNodeOptions{}; + if (opts) { + leaf_node_opts = opt::get(opts).leaf_node_opts; + } + + auto new_priv = next._tree.update( + next._index, leaf_secret, next._group_id, _identity_priv, leaf_node_opts); + + auto ctx = tls::marshal(GroupContext{ + next._suite, + next._group_id, + next._epoch + 1, + next._tree.root_hash(), + next._transcript_hash.confirmed, + next._extensions, + }); + auto path = next._tree.encap(new_priv, ctx, joiner_locations); + + next._tree_priv = new_priv; + commit.path = path; + commit_secret = new_priv.update_secret; + + for (size_t i = 0; i < joiner_locations.size(); i++) { + auto [overlap, shared_path_secret, ok] = + new_priv.shared_path_secret(joiner_locations[i]); + silence_unused(overlap); + silence_unused(ok); + + path_secrets[i] = shared_path_secret; + } + } + + // Create the Commit message and advance the transcripts / key schedule + auto commit_content_auth = + sign(sender, commit, msg_opts.authenticated_data, msg_opts.encrypt); + + next._transcript_hash.update_confirmed(commit_content_auth); + next._epoch += 1; + next.update_epoch_secrets(commit_secret, psks, force_init_secret); + + const auto confirmation_tag = + next._key_schedule.confirmation_tag(next._transcript_hash.confirmed); + commit_content_auth.set_confirmation_tag(confirmation_tag); + + next._transcript_hash.update_interim(commit_content_auth); + + auto commit_message = + protect(std::move(commit_content_auth), msg_opts.padding_size); + + // Complete the GroupInfo and form the Welcome + auto group_info = GroupInfo{ + { + next._suite, + next._group_id, + next._epoch, + next._tree.root_hash(), + next._transcript_hash.confirmed, + next._extensions, + }, + { /* No other extensions */ }, + { confirmation_tag }, + }; + if (opts && opt::get(opts).inline_tree) { + group_info.extensions.add(RatchetTreeExtension{ next._tree }); + } + group_info.sign(next._tree, next._index, next._identity_priv); + + auto welcome = + Welcome{ _suite, next._key_schedule.joiner_secret, psks, group_info }; + for (size_t i = 0; i < joiners.size(); i++) { + welcome.encrypt(joiners[i], path_secrets[i]); + } + + return std::make_tuple(commit_message, welcome, next); +} + +/// +/// Message handlers +/// + +GroupContext +State::group_context() const +{ + return GroupContext{ + _suite, + _group_id, + _epoch, + _tree.root_hash(), + _transcript_hash.confirmed, + _extensions, + }; +} + +std::optional +State::handle(const MLSMessage& msg) +{ + return handle(unwrap(msg), std::nullopt, std::nullopt); +} + +std::optional +State::handle(const MLSMessage& msg, std::optional cached_state) +{ + return handle(unwrap(msg), std::move(cached_state), std::nullopt); +} + +std::optional +State::handle(const ValidatedContent& content_auth) +{ + return handle(content_auth, std::nullopt, std::nullopt); +} + +std::optional +State::handle(const ValidatedContent& content_auth, + std::optional cached_state) +{ + return handle(content_auth, std::move(cached_state), std::nullopt); +} + +std::optional +State::handle(const MLSMessage& msg, + std::optional cached_state, + const std::optional& expected_params) +{ + return handle(unwrap(msg), std::move(cached_state), expected_params); +} + +std::optional +State::handle(const ValidatedContent& val_content, + std::optional cached_state, + const std::optional& expected_params) +{ + // Dispatch on content type + const auto& content_auth = val_content.authenticated_content(); + const auto& content = content_auth.content; + switch (content.content_type()) { + // Proposals get queued, do not result in a state transition + case ContentType::proposal: + cache_proposal(content_auth); + return std::nullopt; + + // Commits are handled in the remainder of this method + case ContentType::commit: + break; + + // Any other content type in this method is an error + default: + throw InvalidParameterError("Invalid content type"); + } + + switch (content.sender.sender_type()) { + case SenderType::member: + case SenderType::new_member_commit: + break; + + default: + throw ProtocolError("Invalid commit sender type"); + } + + auto sender = std::optional(); + if (content.sender.sender_type() == SenderType::member) { + sender = var::get(content.sender.sender).sender; + } + + if (sender == _index) { + if (cached_state) { + // Verify that the cached state is a plausible successor to this state + const auto& next = opt::get(cached_state); + if (next._group_id != _group_id || next._epoch != _epoch + 1 || + next._index != _index) { + throw InvalidParameterError("Invalid successor state"); + } + + return next; + } + + throw InvalidParameterError("Handle own commits with caching"); + } + + // Apply the commit + const auto& commit = var::get(content.content); + const auto proposals = must_resolve(commit.proposals, sender); + + const auto params = infer_commit_type(sender, proposals, expected_params); + auto external_commit = var::holds_alternative(params); + + // Check that a path is present when required + if (path_required(proposals) && !commit.path) { + throw ProtocolError("Path required but not present"); + } + + // Apply the proposals + auto next = successor(); + auto [joiner_locations, psks] = next.apply(proposals); + + // If this is an external commit, add the joiner to the tree and note the + // location where they were added. Also, compute the "externally forced" + // value that we will use for the init_secret (as opposed to the init_secret + // from the key schedule). + auto force_init_secret = std::optional{}; + auto sender_location = LeafIndex{ 0 }; + if (!external_commit) { + sender_location = opt::get(sender); + } else { + // Find where the joiner will be added + sender_location = next._tree.allocate_leaf(); + + // Extract the forced init secret + auto kem_output = commit.valid_external(); + if (!kem_output) { + throw ProtocolError("Invalid external commit"); + } + + force_init_secret = + _key_schedule.receive_external_init(opt::get(kem_output)); + } + + // Decapsulate and apply the UpdatePath, if provided + auto commit_secret = _suite.zero(); + if (commit.path) { + const auto& path = opt::get(commit.path); + + if (!valid(path.leaf_node, LeafNodeSource::commit, sender_location)) { + throw ProtocolError("Commit path has invalid leaf node"); + } + + if (!next._tree.parent_hash_valid(sender_location, path)) { + throw ProtocolError("Commit path has invalid parent hash"); + } + + next._tree.merge(sender_location, path); + + auto ctx = tls::marshal(GroupContext{ + next._suite, + next._group_id, + next._epoch + 1, + next._tree.root_hash(), + next._transcript_hash.confirmed, + next._extensions, + }); + next._tree_priv.decap( + sender_location, next._tree, ctx, path, joiner_locations); + + commit_secret = next._tree_priv.update_secret; + } + + // Update the transcripts and advance the key schedule + next._transcript_hash.update(content_auth); + next._epoch += 1; + next.update_epoch_secrets(commit_secret, { psks }, force_init_secret); + + // Verify the confirmation MAC + const auto confirmation_tag = + next._key_schedule.confirmation_tag(next._transcript_hash.confirmed); + if (!content_auth.check_confirmation_tag(confirmation_tag)) { + throw ProtocolError("Confirmation failed to verify"); + } + + return next; +} + +/// +/// Subgroup branching +/// + +// Parameters: +// * ctor inputs +// * leaf_secret +// * commit_opts +std::tuple +State::create_branch(bytes group_id, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + ExtensionList extensions, + const std::vector& key_packages, + const bytes& leaf_secret, + const CommitOpts& commit_opts) const +{ + // Create new empty group with the appropriate PSK + auto new_group = + State{ std::move(group_id), _suite, std::move(enc_priv), + std::move(sig_priv), leaf_node, std::move(extensions) }; + + new_group.add_resumption_psk(_group_id, _epoch, _key_schedule.resumption_psk); + + // Create Add proposals + auto proposals = stdx::transform( + key_packages, [&](const auto& kp) { return new_group.add_proposal(kp); }); + + // Create PSK proposal + proposals.push_back({ PreSharedKey{ + { ResumptionPSK{ ResumptionPSKUsage::branch, _group_id, _epoch }, + random_bytes(_suite.secret_size()) } } }); + + // Commit the Add and PSK proposals + auto opts = CommitOpts{ + proposals, + commit_opts.inline_tree, + commit_opts.force_path, + commit_opts.leaf_node_opts, + }; + auto [_commit, welcome, state] = new_group.commit( + leaf_secret, opts, {}, RestartCommitParams{ ResumptionPSKUsage::branch }); + return { state, welcome }; +} + +State +State::handle_branch(const HPKEPrivateKey& init_priv, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree) const +{ + auto resumption_psks = + std::map{ { { _group_id, _epoch }, + _key_schedule.resumption_psk } }; + auto branch_state = State{ + init_priv, + std::move(enc_priv), + std::move(sig_priv), + key_package, + welcome, + tree, + {}, + resumption_psks, + }; + + if (branch_state._suite != _suite) { + throw ProtocolError("Attempt to branch with a different ciphersuite"); + } + + if (branch_state._epoch != 1) { + throw ProtocolError("Branch not done at the beginning of the group"); + } + + return branch_state; +} + +State::Tombstone::Tombstone(const State& state_in, ReInit reinit_in) + : epoch_authenticator(state_in.epoch_authenticator()) + , reinit(std::move(reinit_in)) + , prior_group_id(state_in._group_id) + , prior_epoch(state_in._epoch) + , resumption_psk(state_in._key_schedule.resumption_psk) +{ +} + +std::tuple +State::Tombstone::create_welcome(HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const LeafNode& leaf_node, + const std::vector& key_packages, + const bytes& leaf_secret, + const CommitOpts& commit_opts) const +{ + // Create new empty group with the appropriate PSK + auto new_group = + State{ reinit.group_id, reinit.cipher_suite, std::move(enc_priv), + std::move(sig_priv), leaf_node, reinit.extensions }; + + new_group.add_resumption_psk(prior_group_id, prior_epoch, resumption_psk); + + // Create Add proposals + auto proposals = stdx::transform( + key_packages, [&](const auto& kp) { return new_group.add_proposal(kp); }); + + // Create PSK proposal + proposals.push_back({ PreSharedKey{ + { ResumptionPSK{ ResumptionPSKUsage::reinit, prior_group_id, prior_epoch }, + random_bytes(reinit.cipher_suite.secret_size()) } } }); + + // Commit the Add and PSK proposals + auto opts = CommitOpts{ + proposals, + commit_opts.inline_tree, + commit_opts.force_path, + commit_opts.leaf_node_opts, + }; + auto [_commit, welcome, state] = new_group.commit( + leaf_secret, opts, {}, RestartCommitParams{ ResumptionPSKUsage::reinit }); + return { state, welcome }; +} + +State +State::Tombstone::handle_welcome( + const HPKEPrivateKey& init_priv, + HPKEPrivateKey enc_priv, + SignaturePrivateKey sig_priv, + const KeyPackage& key_package, + const Welcome& welcome, + const std::optional& tree) const +{ + auto resumption_psks = + std::map{ { { prior_group_id, prior_epoch }, + resumption_psk } }; + auto new_state = State{ + init_priv, + std::move(enc_priv), + std::move(sig_priv), + key_package, + welcome, + tree, + {}, + resumption_psks, + }; + + if (new_state._suite != reinit.cipher_suite) { + throw ProtocolError("Attempt to reinit with the wrong ciphersuite"); + } + + if (new_state._epoch != 1) { + throw ProtocolError("ReInit not done at the beginning of the group"); + } + + return new_state; +} + +std::tuple +State::reinit_commit(const bytes& leaf_secret, + const std::optional& opts, + const MessageOpts& msg_opts) +{ + // Ensure that either the proposal cache or the inline proposals have a ReInit + // proposal, and no others. + auto reinit_proposal = Proposal{}; + if (_pending_proposals.size() == 1) { + reinit_proposal = _pending_proposals.front().proposal; + } else if (opts && opt::get(opts).extra_proposals.size() == 1) { + reinit_proposal = opt::get(opts).extra_proposals.front(); + } else { + throw ProtocolError("Illegal proposals for reinitialization"); + } + + auto reinit = var::get(reinit_proposal.content); + + // Create the commit + const auto [commit_msg, welcome, new_state] = + commit(leaf_secret, opts, msg_opts, ReInitCommitParams{}); + silence_unused(welcome); + + // Create the Tombstone from the terminal state + return { { new_state, reinit }, commit_msg }; +} + +State::Tombstone +State::handle_reinit_commit(const MLSMessage& commit_msg) +{ + // Verify the signature and process the commit + const auto val_content = unwrap(commit_msg); + const auto& content_auth = val_content.authenticated_content(); + if (!verify(content_auth)) { + throw InvalidParameterError("Message signature failed to verify"); + } + + auto new_state = + opt::get(handle(content_auth, std::nullopt, ReInitCommitParams{})); + + // Extract the ReInit and create the Tombstone + const auto& commit = var::get(content_auth.content.content); + const auto proposals = must_resolve(commit.proposals, std::nullopt); + if (!valid_reinit(proposals)) { + throw ProtocolError("Invalid proposals for reinit"); + } + + const auto& reinit_proposal = proposals.front(); + const auto& reinit = var::get(reinit_proposal.proposal.content); + return Tombstone{ new_state, reinit }; +} + +/// +/// Internals +/// + +LeafIndex +State::apply(const Add& add) +{ + return _tree.add_leaf(add.key_package.leaf_node); +} + +void +State::apply(LeafIndex target, const Update& update) +{ + _tree.update_leaf(target, update.leaf_node); +} + +void +State::apply(LeafIndex target, + const Update& update, + const HPKEPrivateKey& leaf_priv) +{ + _tree.update_leaf(target, update.leaf_node); + _tree_priv.set_leaf_priv(leaf_priv); +} + +LeafIndex +State::apply(const Remove& remove) +{ + if (!_tree.has_leaf(remove.removed)) { + throw ProtocolError("Attempt to remove non-member"); + } + + _tree.blank_path(remove.removed); + return remove.removed; +} + +void +State::apply(const GroupContextExtensions& gce) +{ + // TODO(RLB): Update spec to clarify that you MUST verify that the new + // extensions are compatible with all members. + if (!extensions_supported(gce.group_context_extensions)) { + throw ProtocolError("Unsupported extensions in GroupContextExtensions"); + } + + _extensions = gce.group_context_extensions; +} + +bool +State::extensions_supported(const ExtensionList& exts) const +{ + return _tree.all_leaves([&](auto /* i */, const auto& leaf_node) { + return leaf_node.verify_extension_support(exts); + }); +} + +void +State::cache_proposal(AuthenticatedContent content_auth) +{ + auto ref = _suite.ref(content_auth); + if (stdx::any_of(_pending_proposals, + [&](const auto& cached) { return cached.ref == ref; })) { + return; + } + + auto sender_location = std::optional(); + if (content_auth.content.sender.sender_type() == SenderType::member) { + const auto& sender = content_auth.content.sender.sender; + sender_location = var::get(sender).sender; + } + + const auto& proposal = var::get(content_auth.content.content); + + if (content_auth.content.sender.sender_type() == SenderType::external && + !valid_external_proposal_type(proposal.proposal_type())) { + throw ProtocolError("Invalid external proposal"); + } + + if (!valid(sender_location, proposal)) { + throw ProtocolError("Invalid proposal"); + } + + _pending_proposals.push_back({ + _suite.ref(content_auth), + proposal, + sender_location, + }); +} + +std::optional +State::resolve(const ProposalOrRef& id, + std::optional sender_index) const +{ + if (var::holds_alternative(id.content)) { + return CachedProposal{ + {}, + var::get(id.content), + sender_index, + }; + } + + const auto& ref = var::get(id.content); + for (const auto& cached : _pending_proposals) { + if (cached.ref == ref) { + return cached; + } + } + + return std::nullopt; +} + +std::vector +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +State::must_resolve(const std::vector& ids, + std::optional sender_index) const +{ + auto must_resolve = [&](const auto& id) { + return opt::get(resolve(id, sender_index)); + }; + return stdx::transform(ids, must_resolve); +} + +std::vector +State::resolve(const std::vector& psks) const +{ + return stdx::transform(psks, [&](const auto& psk_id) { + auto get_secret = overloaded{ + [&](const ExternalPSK& ext_psk) { + if (_external_psks.count(ext_psk.psk_id) == 0) { + throw ProtocolError("Unknown external PSK"); + } + + return _external_psks.at(ext_psk.psk_id); + }, + + [&](const ResumptionPSK& res_psk) { + if (res_psk.psk_epoch == _epoch) { + return _key_schedule.resumption_psk; + } + + auto key = std::make_tuple(res_psk.psk_group_id, res_psk.psk_epoch); + if (_resumption_psks.count(key) == 0) { + throw ProtocolError("Unknown Resumption PSK"); + } + + return _resumption_psks.at(key); + }, + }; + + auto secret = var::visit(get_secret, psk_id.content); + return PSKWithSecret{ psk_id, secret }; + }); +} + +std::vector +State::apply(const std::vector& proposals, + Proposal::Type required_type) +{ + auto locations = std::vector{}; + for (const auto& cached : proposals) { + auto proposal_type = cached.proposal.proposal_type(); + if (proposal_type != required_type) { + continue; + } + + switch (proposal_type) { + case ProposalType::add: { + locations.push_back(apply(var::get(cached.proposal.content))); + break; + } + + case ProposalType::update: { + const auto& update = var::get(cached.proposal.content); + + if (!cached.sender) { + throw ProtocolError("Update without target leaf"); + } + + auto target = opt::get(cached.sender); + if (target != _index) { + apply(target, update); + break; + } + + if (!_cached_update) { + throw ProtocolError("Self-update with no cached secret"); + } + + const auto& cached_update = opt::get(_cached_update); + if (update != cached_update.proposal) { + throw ProtocolError("Self-update does not match cached data"); + } + + apply(target, update, cached_update.update_priv); + locations.push_back(target); + break; + } + + case ProposalType::remove: { + const auto& remove = var::get(cached.proposal.content); + locations.push_back(apply(remove)); + break; + } + + case ProposalType::group_context_extensions: { + const auto& gce = + var::get(cached.proposal.content); + apply(gce); + break; + } + + default: + throw ProtocolError("Unsupported proposal type"); + } + } + + // The cached update needs to be reset after applying proposals, so that it is + // in a clean state for the next epoch. + _cached_update.reset(); + + return locations; +} + +std::tuple, std::vector> +State::apply(const std::vector& proposals) +{ + apply(proposals, ProposalType::update); + apply(proposals, ProposalType::remove); + auto joiner_locations = apply(proposals, ProposalType::add); + apply(proposals, ProposalType::group_context_extensions); + + // Extract the PSK proposals and look up the secrets + // TODO(RLB): Factor this out, and also factor the above methods into + // apply_update, apply_remove, etc. + auto psk_ids = std::vector{}; + for (const auto& cached : proposals) { + if (cached.proposal.proposal_type() != ProposalType::psk) { + continue; + } + + const auto& proposal = var::get(cached.proposal.content); + psk_ids.push_back(proposal.psk); + } + auto psks = resolve(psk_ids); + + _tree.truncate(); + _tree_priv.truncate(_tree.size); + _tree.set_hash_all(); + return { joiner_locations, psks }; +} + +/// +/// Message protection +/// + +MLSMessage +State::protect(const bytes& authenticated_data, + const bytes& pt, + size_t padding_size) +{ + auto msg_opts = MessageOpts{ true, authenticated_data, padding_size }; + return protect_full(ApplicationData{ pt }, msg_opts); +} + +std::tuple +State::unprotect(const MLSMessage& ct) +{ + const auto val_content = unwrap(ct); + const auto& content_auth = val_content.authenticated_content(); + + if (!verify(content_auth)) { + throw InvalidParameterError("Message signature failed to verify"); + } + + if (content_auth.content.content_type() != ContentType::application) { + throw ProtocolError("Unprotect of handshake message"); + } + + if (content_auth.wire_format != WireFormat::mls_private_message) { + throw ProtocolError("Application data not sent as PrivateMessage"); + } + + return { + content_auth.content.authenticated_data, + var::get(content_auth.content.content).data, + }; +} + +/// +/// Properties of a proposal list +/// + +bool +State::valid(const LeafNode& leaf_node, + LeafNodeSource required_source, + std::optional index) const +{ + // Verify that the credential in the LeafNode is valid as described in Section + // 5.3.1. + // XXX(RLB) N/A, no credential validation in the library right now + + // Verify the leaf_node_source field: + const auto correct_source = (leaf_node.source() == required_source); + + // Verify that the signature on the LeafNode is valid using signature_key. + auto binding = std::optional{}; + switch (required_source) { + case LeafNodeSource::commit: + case LeafNodeSource::update: + binding = LeafNode::MemberBinding{ _group_id, opt::get(index) }; + break; + + default: + // Nothing to do + break; + } + + const auto signature_valid = leaf_node.verify(_suite, binding); + + // Verify that the LeafNode is compatible with the group's parameters. If the + // GroupContext has a required_capabilities extension, then the required + // extensions, proposals, and credential types MUST be listed in the + // LeafNode's capabilities field. + const auto supports_group_extensions = + leaf_node.verify_extension_support(_extensions); + + // TODO(RLB) Verify the lifetime field + + // Verify that the credential type is supported by all members of the group, + // as specified by the capabilities field of each member's LeafNode, and that + // the capabilities field of this LeafNode indicates support for all the + // credential types currently in use by other members. + // + // Verify that the following fields are unique among the members of the group: + // signature_key + // encryption_key + // + // Note: Uniqueness of signature and encryption keys is assured by the + // tree operations (add/update), so we do not need to verify those here. + const auto mutual_credential_support = + _tree.all_leaves([&](auto /* i */, const auto& leaf) { + return leaf.capabilities.credential_supported(leaf_node.credential) && + leaf_node.capabilities.credential_supported(leaf.credential); + }); + + // Verify that the extensions in the LeafNode are supported by checking that + // the ID for each extension in the extensions field is listed in the + // capabilities.extensions field of the LeafNode. + auto supports_own_extensions = + leaf_node.verify_extension_support(leaf_node.extensions); + + return (signature_valid && supports_group_extensions && correct_source && + mutual_credential_support && supports_own_extensions); +} + +bool +State::valid(const KeyPackage& key_package) const +{ + // Verify that the ciphersuite and protocol version of the KeyPackage match + // those in the GroupContext. + const auto correct_ciphersuite = (key_package.cipher_suite == _suite); + + // Verify that the signature on the KeyPackage is valid using the public key + // in leaf_node.credential. + const auto valid_signature = key_package.verify(); + + // Verify that the leaf_node of the KeyPackage is valid for a KeyPackage + // according to Section 7.3. + const auto leaf_node_valid = + valid(key_package.leaf_node, LeafNodeSource::key_package, std::nullopt); + + // Verify that the value of leaf_node.encryption_key is different from the + // value of the init_key field. + const auto distinct_keys = + (key_package.init_key != key_package.leaf_node.encryption_key); + + return (correct_ciphersuite && valid_signature && leaf_node_valid && + distinct_keys); +} + +bool +State::valid(const Add& add) const +{ + return valid(add.key_package); +} + +bool +State::valid(LeafIndex sender, const Update& update) const +{ + const auto maybe_leaf = _tree.leaf_node(sender); + if (!maybe_leaf) { + return false; + } + + return valid(update.leaf_node, LeafNodeSource::update, sender); +} + +bool +State::valid(const Remove& remove) const +{ + // We mark self-removes invalid here even though a resync Commit will + // sometimes cause them. This is OK because this method is only called from + // the normal proposal list validation method, not the external commit one. + auto in_tree = remove.removed < _tree.size && _tree.has_leaf(remove.removed); + auto not_me = remove.removed != _index; + return in_tree && not_me; +} + +bool +State::valid(const PreSharedKey& psk) const +{ + // External PSKs are allowed if we have the corresponding secret + if (var::holds_alternative(psk.psk.content)) { + const auto& ext_psk = var::get(psk.psk.content); + return _external_psks.count(ext_psk.psk_id) > 0; + } + + // Resumption PSKs are allowed only with usage 'application', and only if we + // have the corresponding secret. + if (var::holds_alternative(psk.psk.content)) { + const auto& res_psk = var::get(psk.psk.content); + if (res_psk.usage != ResumptionPSKUsage::application) { + return false; + } + + const auto key = std::make_tuple(res_psk.psk_group_id, res_psk.psk_epoch); + return res_psk.psk_epoch == _epoch || _resumption_psks.count(key) > 0; + } + + return false; +} + +bool +State::valid(const ReInit& reinit) +{ + // Check that the version and CipherSuite are ones we support + auto supported_version = (reinit.version == ProtocolVersion::mls10); + auto supported_suite = + stdx::contains(all_supported_suites, reinit.cipher_suite.cipher_suite()); + + return supported_version && supported_suite; +} + +bool +State::valid(const ExternalInit& external_init) const +{ + return external_init.kem_output.size() == _suite.hpke().kem.enc_size; +} + +bool +State::valid(const GroupContextExtensions& gce) const +{ + return extensions_supported(gce.group_context_extensions); +} + +bool +State::valid(std::optional sender, const Proposal& proposal) const +{ + const auto specifically_valid = overloaded{ + [&](const Update& update) { return valid(opt::get(sender), update); }, + [&](const auto& proposal) { return valid(proposal); }, + }; + return var::visit(specifically_valid, proposal.content); +} + +bool +State::valid(const std::vector& proposals, + LeafIndex commit_sender, + const CommitParams& params) const +{ + auto specifically = overloaded{ + [&](const NormalCommitParams& /* unused */) { + return valid_normal(proposals, commit_sender); + }, + [&](const ExternalCommitParams& /* unused */) { + return valid_external(proposals); + }, + [&](const RestartCommitParams& params) { + return valid_restart(proposals, params.allowed_usage); + }, + [&](const ReInitCommitParams& /* unused */) { + return valid_reinit(proposals); + }, + }; + + return var::visit(specifically, params); +} + +bool +// NB(RLB): clang-tidy thinks this can be static, but it can't. +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +State::valid_normal(const std::vector& proposals, + LeafIndex commit_sender) const +{ + // It contains an individual proposal that is invalid as specified in Section + // 12.1. + const auto has_invalid_proposal = + stdx::any_of(proposals, [&](const auto& cached) { + return !valid(cached.sender, cached.proposal); + }); + + // It contains an Update proposal generated by the committer. + const auto has_self_update = stdx::any_of(proposals, [&](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::update && + cached.sender == commit_sender; + }); + + // It contains a Remove proposal that removes the committer. + const auto has_self_remove = stdx::any_of(proposals, [&](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::remove && + var::get(cached.proposal.content).removed == commit_sender; + }); + + // It contains multiple Update and/or Remove proposals that apply to the same + // leaf. If the committer has received multiple such proposals they SHOULD + // prefer any Remove received, or the most recent Update if there are no + // Removes. + auto updated_or_removed = std::set{}; + const auto has_dup_update_remove = + stdx::any_of(proposals, [&](const auto& cached) { + auto index = LeafIndex{ 0 }; + switch (cached.proposal.proposal_type()) { + case ProposalType::update: + index = opt::get(cached.sender); + break; + + case ProposalType::remove: + index = var::get(cached.proposal.content).removed; + break; + + default: + return false; + } + + if (stdx::contains(updated_or_removed, index)) { + return true; + } + + updated_or_removed.insert(index); + return false; + }); + + // It contains multiple Add proposals that contain KeyPackages that represent + // the same client according to the application (for example, identical + // signature keys). + auto signature_keys = std::vector{}; + const auto has_dup_signature_key = + stdx::any_of(proposals, [&](const auto& cached) { + if (cached.proposal.proposal_type() != ProposalType::add) { + return false; + } + + auto key_package = var::get(cached.proposal.content).key_package; + auto signature_key = key_package.leaf_node.signature_key; + if (stdx::contains(signature_keys, signature_key)) { + return true; + } + + signature_keys.push_back(signature_key); + return false; + }); + + // It contains an Add proposal with a KeyPackage that represents a client + // already in the group according to the application, unless there is a Remove + // proposal in the list removing the matching client from the group. + // TODO(RLB) + + // It contains multiple PreSharedKey proposals that reference the same + // PreSharedKeyID. + auto psk_ids = std::vector{}; + const auto has_dup_psk_id = stdx::any_of(proposals, [&](const auto& cached) { + if (cached.proposal.proposal_type() != ProposalType::psk) { + return false; + } + + auto psk_id = var::get(cached.proposal.content).psk; + if (stdx::contains(psk_ids, psk_id)) { + return true; + } + + psk_ids.push_back(psk_id); + return false; + }); + + // It contains multiple GroupContextExtensions proposals. + const auto gce_count = stdx::count_if(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == + ProposalType::group_context_extensions; + }); + const auto has_multiple_gce = (gce_count > 1); + + // It contains a ReInit proposal together with any other proposal. If the + // committer has received other proposals during the epoch, they SHOULD prefer + // them over the ReInit proposal, allowing the ReInit to be resent and applied + // in a subsequent epoch. + const auto has_reinit = stdx::any_of(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::reinit; + }); + + // It contains an ExternalInit proposal. + const auto has_external_init = + stdx::any_of(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::external_init; + }); + + // It contains a proposal with a non-default proposal type that is not + // supported by some members of the group that will process the Commit (i.e., + // members being added or removed by the Commit do not need to support the + // proposal type). + // XXX(RLB): N/A, no non-default proposal types + + // After processing the commit the ratchet tree is invalid, in particular, if + // it contains any leaf node that is invalid according to Section 7.3. + // + // NB(RLB): Leaf nodes are already checked in the individual proposal check at + // the top. So the focus here is key uniqueness. We check this by checking + // uniqueness of encryption keys across the Adds and Updates in this list of + // proposals. The keys have already been checked to be distinct from any keys + // already in the tree. + auto enc_keys = std::vector{}; + const auto has_dup_enc_key = stdx::any_of(proposals, [&](const auto& cached) { + const auto get_enc_key = + overloaded{ [](const Add& add) -> std::optional { + return add.key_package.leaf_node.encryption_key; + }, + [](const Update& update) -> std::optional { + return update.leaf_node.encryption_key; + }, + + [](const auto& /* default */) + -> std::optional { return std::nullopt; } }; + auto maybe_enc_key = var::visit(get_enc_key, cached.proposal.content); + if (!maybe_enc_key) { + return false; + } + + const auto& enc_key = opt::get(maybe_enc_key); + if (stdx::contains(enc_keys, enc_key)) { + return true; + } + + enc_keys.push_back(enc_key); + return false; + }); + + return !(has_invalid_proposal || has_self_update || has_self_remove || + has_dup_update_remove || has_dup_signature_key || has_dup_psk_id || + has_multiple_gce || has_reinit || has_external_init || + has_dup_enc_key); +} + +bool +State::valid_reinit(const std::vector& proposals) +{ + // Check that the list contains a ReInit proposal + const auto has_reinit = stdx::any_of(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::reinit; + }); + + // Check whether the list contains any disallowed proposals + const auto has_disallowed = stdx::any_of(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() != ProposalType::reinit; + }); + + return has_reinit && !has_disallowed; +} + +bool +State::valid_restart(const std::vector& proposals, + ResumptionPSKUsage allowed_usage) +{ + // Check that the list has exactly one resumption PSK proposal with the + // allowed usage and any other PSKs are external + auto found_allowed = false; + const auto acceptable_psks = stdx::all_of(proposals, [&](const auto& cached) { + if (cached.proposal.proposal_type() != ProposalType::psk) { + return true; + } + + const auto& psk = var::get(cached.proposal.content); + if (var::holds_alternative(psk.psk.content)) { + return true; + } + + const auto& res_psk = var::get(psk.psk.content); + const auto allowed = res_psk.usage == allowed_usage; + if (found_allowed && allowed) { + return false; + } + + found_allowed = found_allowed || allowed; + return true; + }); + + return acceptable_psks && found_allowed; +} + +bool +State::valid_external_proposal_type(const Proposal::Type proposal_type) +{ + switch (proposal_type) { + case ProposalType::add: + case ProposalType::remove: + case ProposalType::psk: + case ProposalType::reinit: + case ProposalType::group_context_extensions: + return true; + + default: + return false; + } +} + +bool +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +State::valid_external(const std::vector& proposals) const +{ + // Exactly one ExternalInit + auto ext_init_count = stdx::count_if(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::external_init; + }); + auto one_ext_init = (ext_init_count == 1); + + // At most one Remove proposal, with which the joiner removes an old version + // of themselves. If a Remove proposal is present, then the LeafNode in the + // path field of the external commit MUST meet the same criteria as would the + // LeafNode in an Update for the removed leaf (see Section 12.1.2). In + // particular, the credential in the LeafNode MUST present a set of + // identifiers that is acceptable to the application for the removed + // participant. + // TODO(RLB) Verify that Remove is properly formed + auto remove_count = stdx::count_if(proposals, [](const auto& cached) { + return cached.proposal.proposal_type() == ProposalType::remove; + }); + auto no_dup_remove = (remove_count <= 1); + + // Zero or more PreSharedKey proposals. + // No other proposals. + auto no_disallowed = stdx::all_of(proposals, [&](const auto& cached) { + switch (cached.proposal.proposal_type()) { + case ProposalType::external_init: + case ProposalType::remove: + return true; + + case ProposalType::psk: + return valid(var::get(cached.proposal.content)); + + default: + return false; + } + }); + + return one_ext_init && no_dup_remove && no_disallowed; +} + +State::CommitParams +State::infer_commit_type( + const std::optional& sender, + const std::vector& proposals, + const std::optional& expected_params) const +{ + // If an expected type was provided, validate against it + if (expected_params) { + const auto& expected = opt::get(expected_params); + + auto specifically = overloaded{ + [&](const NormalCommitParams& /* unused */) { + return sender && valid_normal(proposals, opt::get(sender)); + }, + [&](const ExternalCommitParams& /* unused */) { + return !sender && valid_external(proposals); + }, + [&](const RestartCommitParams& params) { + return sender && valid_restart(proposals, params.allowed_usage); + }, + [&](const ReInitCommitParams& /* unused */) { + return sender && valid_reinit(proposals); + }, + }; + + if (!var::visit(specifically, expected)) { + throw ProtocolError("Invalid proposal list"); + } + + return expected; + } + + // Otherwise, check to see if this is a valid external or normal commit + if (!sender && valid_external(proposals)) { + return ExternalCommitParams{}; + } + + if (sender && valid_normal(proposals, opt::get(sender))) { + return NormalCommitParams{}; + } + + throw ProtocolError("Invalid proposal list"); +} + +bool +State::path_required(const std::vector& proposals) +{ + static const auto path_required_types = std::set{ + ProposalType::update, + ProposalType::remove, + ProposalType::external_init, + ProposalType::group_context_extensions, + }; + + if (proposals.empty()) { + return true; + } + + return stdx::any_of(proposals, [](const auto& cp) { + return path_required_types.count(cp.proposal.proposal_type()) != 0; + }); +} + +/// +/// Inner logic and convenience functions +/// + +bool +operator==(const State& lhs, const State& rhs) +{ + auto suite = (lhs._suite == rhs._suite); + auto group_id = (lhs._group_id == rhs._group_id); + auto epoch = (lhs._epoch == rhs._epoch); + auto tree = (lhs._tree == rhs._tree); + auto transcript_hash = (lhs._transcript_hash == rhs._transcript_hash); + auto key_schedule = (lhs._key_schedule == rhs._key_schedule); + auto extensions = (lhs._extensions == rhs._extensions); + + return suite && group_id && epoch && tree && transcript_hash && + key_schedule && extensions; +} + +bool +operator!=(const State& lhs, const State& rhs) +{ + return !(lhs == rhs); +} + +void +State::update_epoch_secrets(const bytes& commit_secret, + const std::vector& psks, + const std::optional& force_init_secret) +{ + auto ctx = tls::marshal(GroupContext{ + _suite, + _group_id, + _epoch, + _tree.root_hash(), + _transcript_hash.confirmed, + _extensions, + }); + _key_schedule = + _key_schedule.next(commit_secret, psks, force_init_secret, ctx); + _keys = _key_schedule.encryption_keys(_tree.size); +} + +/// +/// Message encryption and decryption +/// +bool +State::verify_internal(const AuthenticatedContent& content_auth) const +{ + const auto& sender = + var::get(content_auth.content.sender.sender).sender; + auto maybe_leaf = _tree.leaf_node(sender); + if (!maybe_leaf) { + throw InvalidParameterError("Signature from blank node"); + } + + const auto& pub = opt::get(maybe_leaf).signature_key; + return content_auth.verify(_suite, pub, group_context()); +} + +bool +State::verify_external(const AuthenticatedContent& content_auth) const +{ + const auto& ext_sender = + var::get(content_auth.content.sender.sender); + const auto senders_ext = _extensions.find(); + const auto& senders = opt::get(senders_ext).senders; + const auto& pub = senders.at(ext_sender.sender_index).signature_key; + return content_auth.verify(_suite, pub, group_context()); +} + +bool +State::verify_new_member_proposal( + const AuthenticatedContent& content_auth) const +{ + const auto& proposal = var::get(content_auth.content.content); + const auto& add = var::get(proposal.content); + const auto& pub = add.key_package.leaf_node.signature_key; + return content_auth.verify(_suite, pub, group_context()); +} + +bool +State::verify_new_member_commit(const AuthenticatedContent& content_auth) const +{ + const auto& commit = var::get(content_auth.content.content); + const auto& path = opt::get(commit.path); + const auto& pub = path.leaf_node.signature_key; + return content_auth.verify(_suite, pub, group_context()); +} + +bool +State::verify(const AuthenticatedContent& content_auth) const +{ + switch (content_auth.content.sender.sender_type()) { + case SenderType::member: + return verify_internal(content_auth); + + case SenderType::external: + return verify_external(content_auth); + + case SenderType::new_member_proposal: + return verify_new_member_proposal(content_auth); + + case SenderType::new_member_commit: + return verify_new_member_commit(content_auth); + + default: + throw ProtocolError("Invalid sender type"); + } +} + +void +State::add_resumption_psk(const bytes& group_id, epoch_t epoch, bytes secret) +{ + _resumption_psks.insert_or_assign({ group_id, epoch }, std::move(secret)); +} + +void +State::remove_resumption_psk(const bytes& group_id, epoch_t epoch) +{ + _resumption_psks.erase({ group_id, epoch }); +} + +void +State::add_external_psk(const bytes& id, const bytes& secret) +{ + _external_psks.insert_or_assign(id, secret); +} + +void +State::remove_external_psk(const bytes& id) +{ + _external_psks.erase(id); +} + +bytes +State::do_export(const std::string& label, + const bytes& context, + size_t size) const +{ + return _key_schedule.do_export(label, context, size); +} + +GroupInfo +State::group_info(bool inline_tree) const +{ + auto group_info = GroupInfo{ + { + _suite, + _group_id, + _epoch, + _tree.root_hash(), + _transcript_hash.confirmed, + _extensions, + }, + { /* No other extensions */ }, + _key_schedule.confirmation_tag(_transcript_hash.confirmed), + }; + + group_info.extensions.add( + ExternalPubExtension{ _key_schedule.external_priv.public_key }); + + if (inline_tree) { + group_info.extensions.add(RatchetTreeExtension{ _tree }); + } + + group_info.sign(_tree, _index, _identity_priv); + return group_info; +} + +std::vector +State::roster() const +{ + auto leaves = std::vector{}; + leaves.reserve(_tree.size.val); + + _tree.all_leaves([&](auto /* i */, auto leaf) { + leaves.push_back(leaf); + return true; + }); + + return leaves; +} + +bytes +State::epoch_authenticator() const +{ + return _key_schedule.epoch_authenticator; +} + +LeafIndex +State::leaf_for_roster_entry(RosterIndex index) const +{ + auto visited = RosterIndex{ 0 }; + auto found = std::optional{}; + _tree.all_leaves([&](auto i, const auto& /* leaf_node */) { + if (visited == index) { + found = i; + return false; + } + + visited.val += 1; + return true; + }); + + return opt::get(found); +} + +State +State::successor() const +{ + // Copy everything, then clear things that shouldn't be copied + auto next = *this; + next._pending_proposals.clear(); + + // Copy forward a resumption PSK + next.add_resumption_psk(_group_id, _epoch, _key_schedule.resumption_psk); + + return next; +} + +} // namespace mlspp diff --git a/mlspp/src/tree_math.cpp b/mlspp/src/tree_math.cpp new file mode 100755 index 0000000000..eef9423889 --- /dev/null +++ b/mlspp/src/tree_math.cpp @@ -0,0 +1,223 @@ +#include "mls/tree_math.h" +#include "mls/common.h" + +#include + +static const uint32_t one = 0x01; + +static uint32_t +log2(uint32_t x) +{ + if (x == 0) { + return 0; + } + + uint32_t k = 0; + while ((x >> k) > 0) { + k += 1; + } + return k - 1; +} + +namespace mlspp { + +LeafCount::LeafCount(const NodeCount w) +{ + if (w.val == 0) { + val = 0; + return; + } + + if ((w.val & one) == 0) { + throw InvalidParameterError("Only odd node counts describe trees"); + } + + val = (w.val >> one) + 1; +} + +LeafCount +LeafCount::full(const LeafCount n) +{ + auto w = uint32_t(1); + while (w < n.val) { + w <<= 1U; + } + return LeafCount{ w }; +} + +NodeCount::NodeCount(const LeafCount n) + : UInt32(2 * (n.val - 1) + 1) +{ +} + +LeafIndex::LeafIndex(NodeIndex x) + : UInt32(0) +{ + if (x.val % 2 == 1) { + throw InvalidParameterError("Only even node indices describe leaves"); + } + + val = x.val >> 1; // NOLINT(hicpp-signed-bitwise) +} + +NodeIndex +LeafIndex::ancestor(LeafIndex other) const +{ + auto ln = NodeIndex(*this); + auto rn = NodeIndex(other); + if (ln == rn) { + return ln; + } + + uint8_t k = 0; + while (ln != rn) { + ln.val = ln.val >> 1U; + rn.val = rn.val >> 1U; + k += 1; + } + + const uint32_t prefix = ln.val << k; + const uint32_t stop = (1U << uint8_t(k - 1)); + return NodeIndex{ prefix + (stop - 1) }; +} + +NodeIndex::NodeIndex(LeafIndex x) + : UInt32(2 * x.val) +{ +} + +NodeIndex +NodeIndex::root(LeafCount n) +{ + if (n.val == 0) { + throw std::runtime_error("Root for zero-size tree is undefined"); + } + + auto w = NodeCount(n); + return NodeIndex{ (one << log2(w.val)) - 1 }; +} + +bool +NodeIndex::is_leaf() const +{ + return val % 2 == 0; +} + +bool +NodeIndex::is_below(NodeIndex other) const +{ + auto lx = level(); + auto ly = other.level(); + return lx <= ly && (val >> (ly + 1) == other.val >> (ly + 1)); +} + +NodeIndex +NodeIndex::left() const +{ + if (is_leaf()) { + return *this; + } + + // The clang analyzer doesn't realize that is_leaf() assures that level >= 1 + // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) + return NodeIndex{ val ^ (one << (level() - 1)) }; +} + +NodeIndex +NodeIndex::right() const +{ + if (is_leaf()) { + return *this; + } + + return NodeIndex{ val ^ (uint32_t(0x03) << (level() - 1)) }; +} + +NodeIndex +NodeIndex::parent() const +{ + auto k = level(); + return NodeIndex{ (val | (one << k)) & ~(one << (k + 1)) }; +} + +NodeIndex +NodeIndex::sibling() const +{ + return sibling(parent()); +} + +NodeIndex +NodeIndex::sibling(NodeIndex ancestor) const +{ + if (!is_below(ancestor)) { + throw InvalidParameterError("Node is not below claimed ancestor"); + } + + auto l = ancestor.left(); + auto r = ancestor.right(); + + if (is_below(l)) { + return r; + } + + return l; +} + +std::vector +NodeIndex::dirpath(LeafCount n) +{ + if (val >= NodeCount(n).val) { + throw InvalidParameterError("Request for dirpath outside of tree"); + } + + auto d = std::vector{}; + + auto r = root(n); + if (*this == r) { + return d; + } + + auto p = parent(); + while (p.val != r.val) { + d.push_back(p); + p = p.parent(); + } + + // Include the root except in a one-member tree + if (val != r.val) { + d.push_back(p); + } + + return d; +} + +std::vector +NodeIndex::copath(LeafCount n) +{ + auto d = dirpath(n); + if (d.empty()) { + return {}; + } + + // Prepend leaf; omit root + d.insert(d.begin(), *this); + d.pop_back(); + + return stdx::transform(d, [](auto x) { return x.sibling(); }); +} + +uint32_t +NodeIndex::level() const +{ + if ((val & one) == 0) { + return 0; + } + + uint32_t k = 0; + while (((val >> k) & one) == 1) { + k += 1; + } + return k; +} + +} // namespace mlspp diff --git a/mlspp/src/treekem.cpp b/mlspp/src/treekem.cpp new file mode 100755 index 0000000000..fe3aebc2a2 --- /dev/null +++ b/mlspp/src/treekem.cpp @@ -0,0 +1,1127 @@ +#include + +#if ENABLE_TREE_DUMP +#include +#endif + +namespace mlspp { + +// Utility method used for removing leaves from a resolution +static void +remove_leaves(std::vector& res, const std::vector& except) +{ + for (const auto& leaf : except) { + auto it = std::find(res.begin(), res.end(), NodeIndex(leaf)); + if (it == res.end()) { + continue; + } + + res.erase(it); + } +} + +/// +/// Node +/// + +const HPKEPublicKey& +Node::public_key() const +{ + const auto get_key = overloaded{ + [](const LeafNode& n) -> const HPKEPublicKey& { return n.encryption_key; }, + [](const ParentNode& n) -> const HPKEPublicKey& { return n.public_key; }, + }; + return var::visit(get_key, node); +} + +std::optional +Node::parent_hash() const +{ + const auto get_leaf_ph = overloaded{ + [](const ParentHash& ph) -> std::optional { return ph.parent_hash; }, + [](const auto& /* other */) -> std::optional { + return std::nullopt; + }, + }; + + const auto get_ph = overloaded{ + [&](const LeafNode& node) -> std::optional { + return var::visit(get_leaf_ph, node.content); + }, + [](const ParentNode& node) -> std::optional { + return node.parent_hash; + }, + }; + + return var::visit(get_ph, node); +} + +/// +/// TreeKEMPrivateKey +/// + +TreeKEMPrivateKey +TreeKEMPrivateKey::solo(CipherSuite suite, + LeafIndex index, + HPKEPrivateKey leaf_priv) +{ + auto priv = TreeKEMPrivateKey{ suite, index, {}, {}, {} }; + priv.private_key_cache.insert({ NodeIndex(index), std::move(leaf_priv) }); + return priv; +} + +TreeKEMPrivateKey +TreeKEMPrivateKey::create(const TreeKEMPublicKey& pub, + LeafIndex from, + const bytes& leaf_secret) +{ + auto priv = TreeKEMPrivateKey{ pub.suite, from, {}, {}, {} }; + priv.implant(pub, NodeIndex(from), leaf_secret); + return priv; +} + +TreeKEMPrivateKey +TreeKEMPrivateKey::joiner(const TreeKEMPublicKey& pub, + LeafIndex index, + HPKEPrivateKey leaf_priv, + NodeIndex intersect, + const std::optional& path_secret) +{ + auto priv = TreeKEMPrivateKey{ pub.suite, index, {}, {}, {} }; + priv.private_key_cache.insert({ NodeIndex(index), std::move(leaf_priv) }); + if (path_secret) { + priv.implant(pub, intersect, opt::get(path_secret)); + } + return priv; +} + +void +TreeKEMPrivateKey::implant(const TreeKEMPublicKey& pub, + NodeIndex start, + const bytes& path_secret) +{ + const auto fdp = pub.filtered_direct_path(start); + auto secret = path_secret; + + path_secrets.insert_or_assign(start, secret); + private_key_cache.erase(start); + + for (const auto& [n, _res] : fdp) { + secret = pub.suite.derive_secret(secret, "path"); + path_secrets.insert_or_assign(n, secret); + private_key_cache.erase(n); + } + + update_secret = pub.suite.derive_secret(secret, "path"); +} + +std::optional +TreeKEMPrivateKey::private_key(NodeIndex n) const +{ + auto pki = private_key_cache.find(n); + if (pki != private_key_cache.end()) { + return pki->second; + } + + auto i = path_secrets.find(n); + if (i == path_secrets.end()) { + return std::nullopt; + } + + auto node_secret = suite.derive_secret(i->second, "node"); + return HPKEPrivateKey::derive(suite, node_secret); +} + +bool +TreeKEMPrivateKey::have_private_key(NodeIndex n) const +{ + auto path_secret = path_secrets.find(n) != path_secrets.end(); + auto cached_priv = private_key_cache.find(n) != private_key_cache.end(); + return path_secret || cached_priv; +} + +std::optional +TreeKEMPrivateKey::private_key(NodeIndex n) +{ + auto priv = static_cast(*this).private_key(n); + if (priv) { + private_key_cache.insert_or_assign(n, opt::get(priv)); + } + return priv; +} + +void +TreeKEMPrivateKey::set_leaf_priv(HPKEPrivateKey priv) +{ + auto n = NodeIndex(index); + path_secrets.erase(n); + private_key_cache.insert_or_assign(n, std::move(priv)); +} + +std::tuple +TreeKEMPrivateKey::shared_path_secret(LeafIndex to) const +{ + auto n = index.ancestor(to); + auto i = path_secrets.find(n); + if (i == path_secrets.end()) { + return std::make_tuple(n, bytes{}, false); + } + + return std::make_tuple(n, i->second, true); +} + +#if ENABLE_TREE_DUMP +// XXX(RLB) This should ultimately be deleted, but it is handy for interop +// debugging, so I'm keeping it around for now. If re-enabled, you'll also need +// to add the appropriate declarations to treekem.h and include + +void +TreeKEMPrivateKey::dump() const +{ + for (const auto& [node, _] : path_secrets) { + private_key(node); + } + + std::cout << "Tree (priv):" << std::endl; + std::cout << " Index: " << NodeIndex(index).val << std::endl; + + std::cout << " Secrets: " << std::endl; + for (const auto& [n, path_secret] : path_secrets) { + auto node_secret = suite.derive_secret(path_secret, "node"); + auto sk = HPKEPrivateKey::derive(suite, node_secret); + + auto psm = to_hex(path_secret).substr(0, 8); + auto pkm = to_hex(sk.public_key.data).substr(0, 8); + std::cout << " " << n.val << " => " << psm << " => " << pkm << std::endl; + } + + std::cout << " Cached key pairs: " << std::endl; + for (const auto& [n, sk] : private_key_cache) { + auto pkm = to_hex(sk.public_key.data).substr(0, 8); + std::cout << " " << n.val << " => " << pkm << std::endl; + } +} + +void +TreeKEMPublicKey::dump() const +{ + std::cout << "Tree:" << std::endl; + auto width = NodeCount(size); + for (auto i = NodeIndex{ 0 }; i.val < width.val; i.val++) { + printf(" %03d : ", i.val); // NOLINT + if (!node_at(i).blank()) { + auto pkRm = to_hex(opt::get(node_at(i).node).public_key().data); + std::cout << pkRm.substr(0, 8); + } else { + std::cout << " "; + } + + std::cout << " | "; + for (uint32_t j = 0; j < i.level(); j++) { + std::cout << " "; + } + + if (!node_at(i).blank()) { + std::cout << "X"; + + if (!i.is_leaf()) { + auto parent = node_at(i).parent_node(); + std::cout << " ["; + for (const auto u : parent.unmerged_leaves) { + std::cout << u.val << ", "; + } + std::cout << "]"; + } + + } else { + std::cout << "_"; + } + + std::cout << std::endl; + } +} +#endif + +void +TreeKEMPrivateKey::decap(LeafIndex from, + const TreeKEMPublicKey& pub, + const bytes& context, + const UpdatePath& path, + const std::vector& except) +{ + // Identify which node in the path secret we will be decrypting + auto ni = NodeIndex(index); + auto dp = pub.filtered_direct_path(NodeIndex(from)); + if (dp.size() != path.nodes.size()) { + throw ProtocolError("Malformed direct path"); + } + + size_t dpi = 0; + auto overlap_node = NodeIndex{}; + auto res = std::vector{}; + for (dpi = 0; dpi < dp.size(); dpi++) { + const auto [dpn, dpres] = dp[dpi]; + if (ni.is_below(dpn)) { + overlap_node = dpn; + res = dpres; + break; + } + } + + if (dpi == dp.size()) { + throw ProtocolError("No overlap in path"); + } + + // Identify which node in the resolution of the copath we will use to decrypt + remove_leaves(res, except); + if (res.size() != path.nodes[dpi].encrypted_path_secret.size()) { + throw ProtocolError("Malformed direct path node"); + } + + size_t resi = 0; + const NodeIndex res_overlap_node; + for (resi = 0; resi < res.size(); resi++) { + if (have_private_key(res[resi])) { + break; + } + } + + if (resi == res.size()) { + throw ProtocolError("No private key to decrypt path secret"); + } + + // Decrypt and implant + auto priv = opt::get(private_key(res[resi])); + auto path_secret = priv.decrypt(suite, + encrypt_label::update_path_node, + context, + path.nodes[dpi].encrypted_path_secret[resi]); + implant(pub, overlap_node, path_secret); + + // Check that the resulting state is consistent with the public key + if (!consistent(pub)) { + throw ProtocolError("TreeKEMPublicKey inconsistent with TreeKEMPrivateKey"); + } +} + +void +TreeKEMPrivateKey::truncate(LeafCount size) +{ + auto ni = NodeIndex(LeafIndex{ size.val - 1 }); + auto to_remove = std::vector{}; + for (const auto& entry : path_secrets) { + if (entry.first.val > ni.val) { + to_remove.push_back(entry.first); + } + } + + for (auto n : to_remove) { + path_secrets.erase(n); + private_key_cache.erase(n); + } +} + +bool +TreeKEMPrivateKey::consistent(const TreeKEMPrivateKey& other) const +{ + if (suite != other.suite) { + return false; + } + + if (update_secret != other.update_secret) { + return false; + } + + const auto match_if_present = [&](const auto& entry) { + auto other_entry = other.path_secrets.find(entry.first); + if (other_entry == other.path_secrets.end()) { + return true; + } + + return entry.second == other_entry->second; + }; + return stdx::all_of(path_secrets, match_if_present); +} + +bool +TreeKEMPrivateKey::consistent(const TreeKEMPublicKey& other) const +{ + if (suite != other.suite) { + return false; + } + + for (const auto& [node, _] : path_secrets) { + private_key(node); + } + + return stdx::all_of(private_key_cache, [other](const auto& entry) { + const auto& [node, priv] = entry; + const auto& opt_node = other.node_at(node).node; + if (!opt_node) { + // It's OK for a TreeKEMPrivateKey to have private keys + // for nodes that are blank in the TreeKEMPublicKey. + // This will happen traniently during Commit + // processing, since proposals will be applied in the + // public tree and not in the private tree. + return true; + } + + const auto& pub = opt::get(opt_node).public_key(); + return priv.public_key == pub; + }); +} + +/// +/// TreeKEMPublicKey +/// + +TreeKEMPublicKey::TreeKEMPublicKey(CipherSuite suite_in) + : suite(suite_in) +{ +} + +LeafIndex +TreeKEMPublicKey::allocate_leaf() +{ + // Find the leftmost blank leaf node + auto index = LeafIndex(0); + while (index.val < size.val && !node_at(index).blank()) { + index.val++; + } + + // Extend the tree if necessary + if (index.val >= size.val) { + if (size.val == 0) { + size.val = 1; + nodes.resize(1); + } else { + size.val *= 2; + nodes.resize(2 * nodes.size() + 1); + } + } + + return index; +} + +LeafIndex +TreeKEMPublicKey::add_leaf(const LeafNode& leaf) +{ + // Check that the leaf node's keys are not already present in the tree + if (exists_in_tree(leaf.encryption_key, std::nullopt)) { + throw InvalidParameterError("Duplicate encryption key"); + } + + if (exists_in_tree(leaf.signature_key, std::nullopt)) { + throw InvalidParameterError("Duplicate signature key"); + } + + // Allocate a blank leaf for this node + const auto index = allocate_leaf(); + + // Set the leaf + node_at(index).node = Node{ leaf }; + + // Update the unmerged list + for (auto& n : NodeIndex(index).dirpath(size)) { + if (!node_at(n).node) { + continue; + } + + auto& parent = var::get(opt::get(node_at(n).node).node); + + // Insert into unmerged leaves while maintaining order + const auto insert_point = stdx::upper_bound(parent.unmerged_leaves, index); + parent.unmerged_leaves.insert(insert_point, index); + } + + clear_hash_path(index); + return index; +} + +void +TreeKEMPublicKey::update_leaf(LeafIndex index, const LeafNode& leaf) +{ + // Check that the leaf node's keys are not already present in the tree, except + // for the signature key, which is allowed to repeat. + if (exists_in_tree(leaf.encryption_key, std::nullopt)) { + throw InvalidParameterError("Duplicate encryption key"); + } + + if (exists_in_tree(leaf.signature_key, index)) { + throw InvalidParameterError("Duplicate signature key"); + } + + blank_path(index); + node_at(NodeIndex(index)).node = Node{ leaf }; + clear_hash_path(index); +} + +void +TreeKEMPublicKey::blank_path(LeafIndex index) +{ + if (nodes.empty()) { + return; + } + + auto ni = NodeIndex(index); + node_at(ni).node.reset(); + for (auto n : ni.dirpath(size)) { + node_at(n).node.reset(); + } + + clear_hash_path(index); +} + +void +TreeKEMPublicKey::merge(LeafIndex from, const UpdatePath& path) +{ + update_leaf(from, path.leaf_node); + + auto dp = filtered_direct_path(NodeIndex(from)); + if (dp.size() != path.nodes.size()) { + throw ProtocolError("Malformed direct path"); + } + + auto ph = parent_hashes(from, dp, path.nodes); + for (size_t i = 0; i < dp.size(); i++) { + auto [n, _res] = dp[i]; + + auto parent_hash = bytes{}; + if (i < dp.size() - 1) { + parent_hash = ph[i + 1]; + } + + node_at(n).node = + Node{ ParentNode{ path.nodes[i].public_key, parent_hash, {} } }; + } + + set_hash_all(); +} + +void +TreeKEMPublicKey::set_hash_all() +{ + auto r = NodeIndex::root(size); + get_hash(r); +} + +bytes +TreeKEMPublicKey::root_hash() const +{ + auto r = NodeIndex::root(size); + if (hashes.count(r) == 0) { + throw InvalidParameterError("Root hash not set"); + } + + return hashes.at(r); +} + +bool +TreeKEMPublicKey::has_parent_hash(NodeIndex child, const bytes& target_ph) const +{ + const auto res = resolve(child); + return stdx::any_of(res, [&](auto nr) { + return opt::get(node_at(nr).node).parent_hash() == target_ph; + }); +} + +bool +TreeKEMPublicKey::parent_hash_valid() const +{ + auto cache = TreeHashCache{}; + + auto width = NodeCount(size); + auto height = NodeIndex::root(size).level(); + for (auto level = uint32_t(1); level <= height; level++) { + auto stride = uint32_t(2) << level; + auto start = NodeIndex{ (stride >> 1U) - 1 }; + + for (auto p = start; p.val < width.val; p.val += stride) { + if (node_at(p).blank()) { + continue; + } + + auto l = p.left(); + auto r = p.right(); + + auto lh = original_parent_hash(cache, p, r); + auto rh = original_parent_hash(cache, p, l); + + if (!has_parent_hash(l, lh) && !has_parent_hash(r, rh)) { + dump(); + return false; + } + } + } + return true; +} + +std::vector +TreeKEMPublicKey::resolve(NodeIndex index) const +{ + auto at_leaf = (index.level() == 0); + if (!node_at(index).blank()) { + auto out = std::vector{ index }; + if (index.is_leaf()) { + return out; + } + + const auto& node = node_at(index); + auto unmerged = + stdx::transform(node.parent_node().unmerged_leaves, + [](LeafIndex x) { return NodeIndex(x); }); + + out.insert(out.end(), unmerged.begin(), unmerged.end()); + return out; + } + + if (at_leaf) { + return {}; + } + + auto l = resolve(index.left()); + auto r = resolve(index.right()); + l.insert(l.end(), r.begin(), r.end()); + return l; +} + +TreeKEMPublicKey::FilteredDirectPath +TreeKEMPublicKey::filtered_direct_path(NodeIndex index) const +{ + auto fdp = FilteredDirectPath{}; + + const auto cp = index.copath(size); + auto last = index; + for (auto n : cp) { + const auto p = n.parent(); + const auto res = resolve(n); + last = p; + if (res.empty()) { + continue; + } + + fdp.emplace_back(p, res); + } + + return fdp; +} + +bool +TreeKEMPublicKey::has_leaf(LeafIndex index) const +{ + return !node_at(index).blank(); +} + +std::optional +TreeKEMPublicKey::find(const LeafNode& leaf) const +{ + for (LeafIndex i{ 0 }; i < size; i.val++) { + const auto& node = node_at(i); + if (!node.blank() && node.leaf_node() == leaf) { + return i; + } + } + + return std::nullopt; +} + +std::optional +TreeKEMPublicKey::leaf_node(LeafIndex index) const +{ + const auto& node = node_at(index); + if (node.blank()) { + return std::nullopt; + } + + return node.leaf_node(); +} + +TreeKEMPrivateKey +TreeKEMPublicKey::update(LeafIndex from, + const bytes& leaf_secret, + const bytes& group_id, + const SignaturePrivateKey& sig_priv, + const LeafNodeOptions& opts) +{ + // Grab information about the sender + const auto& leaf_node = node_at(from); + if (leaf_node.blank()) { + throw InvalidParameterError("Cannot update from blank node"); + } + + // Generate path secrets + auto priv = TreeKEMPrivateKey::create(*this, from, leaf_secret); + auto dp = filtered_direct_path(NodeIndex(from)); + + // Encrypt path secrets to the copath, forming a stub UpdatePath with no + // encryptions + auto path_nodes = stdx::transform(dp, [&](const auto& dpn) { + auto [n, _res] = dpn; + + auto path_secret = priv.path_secrets.at(n); + auto node_priv = opt::get(priv.private_key(n)); + + return UpdatePathNode{ node_priv.public_key, {} }; + }); + + // Update and re-sign the leaf_node + auto ph = parent_hashes(from, dp, path_nodes); + auto ph0 = bytes{}; + if (!ph.empty()) { + ph0 = ph[0]; + } + + auto leaf_pub = opt::get(priv.private_key(NodeIndex(from))).public_key; + auto new_leaf = leaf_node.leaf_node().for_commit( + suite, group_id, from, leaf_pub, ph0, opts, sig_priv); + + // Merge the changes into the tree + merge(from, UpdatePath{ std::move(new_leaf), std::move(path_nodes) }); + + return priv; +} + +UpdatePath +TreeKEMPublicKey::encap(const TreeKEMPrivateKey& priv, + const bytes& context, + const std::vector& except) const +{ + auto dp = filtered_direct_path(NodeIndex(priv.index)); + + // Encrypt path secrets to the copath + auto path_nodes = stdx::transform(dp, [&](const auto& dpn) { + // We need the copy here so that we can modify the resolution. + // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) + auto [n, res] = dpn; + remove_leaves(res, except); + + auto path_secret = priv.path_secrets.at(n); + auto node_priv = opt::get(priv.private_key(n)); + + auto ct = stdx::transform(res, [&](auto nr) { + const auto& node_pub = opt::get(node_at(nr).node).public_key(); + return node_pub.encrypt( + suite, encrypt_label::update_path_node, context, path_secret); + }); + + return UpdatePathNode{ node_priv.public_key, std::move(ct) }; + }); + + // Package everything into an UpdatePath + auto new_leaf = opt::get(leaf_node(priv.index)); + auto path = UpdatePath{ new_leaf, std::move(path_nodes) }; + + return path; +} + +void +TreeKEMPublicKey::truncate() +{ + if (size.val == 0) { + return; + } + + // Clear the parent hashes across blank leaves before truncating + auto index = LeafIndex{ size.val - 1 }; + for (; index.val > 0; index.val--) { + if (!node_at(index).blank()) { + break; + } + clear_hash_path(index); + } + + if (node_at(index).blank()) { + nodes.clear(); + return; + } + + // Remove the right subtree until the tree is of minimal size + while (size.val / 2 > index.val) { + nodes.resize(nodes.size() / 2); + size.val /= 2; + } +} + +OptionalNode& +TreeKEMPublicKey::node_at(NodeIndex n) +{ + auto width = NodeCount(size); + if (n.val >= width.val) { + throw InvalidParameterError("Node index not in tree"); + } + + if (n.val >= nodes.size()) { + return blank_node; + } + + return nodes.at(n.val); +} + +const OptionalNode& +TreeKEMPublicKey::node_at(NodeIndex n) const +{ + auto width = NodeCount(size); + if (n.val >= width.val) { + throw InvalidParameterError("Node index not in tree"); + } + + if (n.val >= nodes.size()) { + return blank_node; + } + + return nodes.at(n.val); +} + +OptionalNode& +TreeKEMPublicKey::node_at(LeafIndex n) +{ + return node_at(NodeIndex(n)); +} + +const OptionalNode& +TreeKEMPublicKey::node_at(LeafIndex n) const +{ + return node_at(NodeIndex(n)); +} + +void +TreeKEMPublicKey::clear_hash_all() +{ + hashes.clear(); +} + +void +TreeKEMPublicKey::clear_hash_path(LeafIndex index) +{ + auto dp = NodeIndex(index).dirpath(size); + hashes.erase(NodeIndex(index)); + for (auto n : dp) { + hashes.erase(n); + } +} + +struct LeafNodeHashInput +{ + LeafIndex leaf_index; + std::optional leaf_node; + TLS_SERIALIZABLE(leaf_index, leaf_node) +}; + +struct ParentNodeHashInput +{ + std::optional parent_node; + const bytes& left_hash; + const bytes& right_hash; + TLS_SERIALIZABLE(parent_node, left_hash, right_hash) +}; + +struct TreeHashInput +{ + var::variant node; + TLS_SERIALIZABLE(node); + TLS_TRAITS(tls::variant) +}; + +const bytes& +TreeKEMPublicKey::get_hash(NodeIndex index) +{ + if (hashes.count(index) > 0) { + return hashes.at(index); + } + + auto hash_input = bytes{}; + const auto& node = node_at(index); + if (index.level() == 0) { + auto input = LeafNodeHashInput{ LeafIndex(index), {} }; + if (!node.blank()) { + input.leaf_node = node.leaf_node(); + } + + hash_input = tls::marshal(TreeHashInput{ input }); + } else { + auto input = ParentNodeHashInput{ + {}, + get_hash(index.left()), + get_hash(index.right()), + }; + + if (!node.blank()) { + input.parent_node = node.parent_node(); + } + + hash_input = tls::marshal(TreeHashInput{ input }); + } + + auto hash = suite.digest().hash(hash_input); + hashes.insert_or_assign(index, hash); + return hashes.at(index); +} + +// struct { +// HPKEPublicKey encryption_key; +// opaque parent_hash; +// opaque original_sibling_tree_hash; +// } ParentHashInput; +struct ParentHashInput +{ + const HPKEPublicKey& public_key; + const bytes& parent_hash; + const bytes& original_child_resolution; + + TLS_SERIALIZABLE(public_key, parent_hash, original_child_resolution) +}; + +bytes +TreeKEMPublicKey::parent_hash(const ParentNode& parent, + NodeIndex copath_child) const +{ + if (hashes.count(copath_child) == 0) { + throw InvalidParameterError("Child hash not set"); + } + + auto hash_input = ParentHashInput{ + parent.public_key, + parent.parent_hash, + hashes.at(copath_child), + }; + + return suite.digest().hash(tls::marshal(hash_input)); +} + +std::vector +TreeKEMPublicKey::parent_hashes( + LeafIndex from, + const FilteredDirectPath& fdp, + const std::vector& path_nodes) const +{ + // An empty filtered direct path indicates a one-member tree, since there's + // nobody else there to encrypt with. In this special case, there's no + // parent hashing to be done. + if (fdp.empty()) { + return {}; + } + + // The list of nodes for whom parent hashes are computed, namely: Direct path + // excluding the last entry, including leaf + auto from_node = NodeIndex(from); + auto dp = fdp; + auto [last, _res_last] = dp.back(); + dp.pop_back(); + dp.insert(dp.begin(), { from_node, {} }); + + if (dp.size() != path_nodes.size()) { + throw ProtocolError("Malformed UpdatePath"); + } + + // Parent hash for all the parents, starting from the last entry of the + // filtered direct path + auto last_hash = bytes{}; + auto ph = std::vector(dp.size()); + for (int i = static_cast(dp.size()) - 1; i >= 0; i--) { + auto [n, _res] = dp[i]; + auto s = n.sibling(last); + + auto parent_node = ParentNode{ path_nodes[i].public_key, last_hash, {} }; + last_hash = parent_hash(parent_node, s); + ph[i] = last_hash; + + last = n; + } + + return ph; +} + +const bytes& +TreeKEMPublicKey::original_tree_hash(TreeHashCache& cache, + NodeIndex index, + std::vector parent_except) const +{ + // Scope the unmerged leaves list down to this subtree + auto except = std::vector{}; + std::copy_if(parent_except.begin(), + parent_except.end(), + std::back_inserter(except), + [&](auto i) { return NodeIndex(i).is_below(index); }); + + auto have_local_changes = !except.empty(); + + // If there are no local changes, then we can use the cached tree hash + if (!have_local_changes) { + return hashes.at(index); + } + + // If this method has been called before with the same number of excluded + // leaves (which implies the same set), then use the cached value. + if (auto it = cache.find(index); it != cache.end()) { + const auto& [key, value] = *it; + const auto& [except_size, hash] = value; + if (except_size == except.size()) { + return hash; + } + } + + // If there is no entry in either cache, recompute the value + auto hash = bytes{}; + if (index.is_leaf()) { + // A leaf node with local changes is by definition excluded from the parent + // hash. So we return the hash of an empty leaf. + auto leaf_hash_input = LeafNodeHashInput{ LeafIndex(index), std::nullopt }; + hash = suite.digest().hash(tls::marshal(TreeHashInput{ leaf_hash_input })); + } else { + // If there is no cached value, recalculate the child hashes with the + // specified `except` list, removing the `except` list from + // `unmerged_leaves`. + auto parent_hash_input = ParentNodeHashInput{ + std::nullopt, + original_tree_hash(cache, index.left(), except), + original_tree_hash(cache, index.right(), except), + }; + + if (!node_at(index).blank()) { + parent_hash_input.parent_node = node_at(index).parent_node(); + auto& unmerged_leaves = + opt::get(parent_hash_input.parent_node).unmerged_leaves; + auto end = std::remove_if( + unmerged_leaves.begin(), unmerged_leaves.end(), [&](auto leaf) { + return std::count(except.begin(), except.end(), leaf) != 0; + }); + unmerged_leaves.erase(end, unmerged_leaves.end()); + } + + hash = + suite.digest().hash(tls::marshal(TreeHashInput{ parent_hash_input })); + } + + cache.insert_or_assign(index, std::make_pair(except.size(), hash)); + return cache.at(index).second; +} + +bytes +TreeKEMPublicKey::original_parent_hash(TreeHashCache& cache, + NodeIndex parent, + NodeIndex sibling) const +{ + const auto& parent_node = node_at(parent).parent_node(); + const auto& unmerged = parent_node.unmerged_leaves; + const auto& sibling_hash = original_tree_hash(cache, sibling, unmerged); + + return suite.digest().hash(tls::marshal(ParentHashInput{ + parent_node.public_key, + parent_node.parent_hash, + sibling_hash, + })); +} + +bool +TreeKEMPublicKey::parent_hash_valid(LeafIndex from, + const UpdatePath& path) const +{ + auto fdp = filtered_direct_path(NodeIndex(from)); + auto hash_chain = parent_hashes(from, fdp, path.nodes); + auto leaf_ph = + var::visit(overloaded{ + [](const ParentHash& ph) -> std::optional { + return ph.parent_hash; + }, + [](const auto& /* other */) -> std::optional { + return std::nullopt; + }, + }, + path.leaf_node.content); + + // If there are no nodes to hash, then ParentHash MUST be omitted + if (hash_chain.empty()) { + return !leaf_ph; + } + + return leaf_ph && opt::get(leaf_ph) == hash_chain[0]; +} + +bool +TreeKEMPublicKey::exists_in_tree(const HPKEPublicKey& key, + std::optional except) const +{ + return any_leaf([&](auto i, const auto& node) { + return i != except && node.encryption_key == key; + }); +} + +bool +TreeKEMPublicKey::exists_in_tree(const SignaturePublicKey& key, + std::optional except) const +{ + return any_leaf([&](auto i, const auto& node) { + return i != except && node.signature_key == key; + }); +} + +tls::ostream& +operator<<(tls::ostream& str, const TreeKEMPublicKey& obj) +{ + // Empty tree + if (obj.size.val == 0) { + return str << std::vector{}; + } + + LeafIndex cut = LeafIndex{ obj.size.val - 1 }; + while (cut.val > 0 && obj.node_at(cut).blank()) { + cut.val -= 1; + } + + const auto begin = obj.nodes.begin(); + const auto end = begin + NodeIndex(cut).val + 1; + const auto view = std::vector(begin, end); + return str << view; +} + +tls::istream& +operator>>(tls::istream& str, TreeKEMPublicKey& obj) +{ + // Read the node list + str >> obj.nodes; + if (obj.nodes.empty()) { + return str; + } + + // Verify that the tree is well-formed and minimal + if (obj.nodes.size() % 2 == 0) { + throw ProtocolError("Malformed ratchet tree: even number of nodes"); + } + + if (obj.nodes.back().blank()) { + throw ProtocolError("Ratchet tree does not use minimal encoding"); + } + + // Adjust the size value to fit the non-blank nodes + obj.size.val = 1; + while (NodeCount(obj.size).val < obj.nodes.size()) { + obj.size.val *= 2; + } + + // Add blank nodes to the end + obj.nodes.resize(NodeCount(obj.size).val); + + // Verify the basic structure of the tree is sane + for (size_t i = 0; i < obj.nodes.size(); i++) { + if (obj.nodes[i].blank()) { + continue; + } + + const auto& node = opt::get(obj.nodes[i].node).node; + auto at_leaf = (i % 2 == 0); + auto holds_leaf = var::holds_alternative(node); + auto holds_parent = var::holds_alternative(node); + + if (at_leaf && !holds_leaf) { + throw InvalidParameterError("Parent node in leaf node position"); + } + + if (!at_leaf && !holds_parent) { + throw InvalidParameterError("Leaf node in parent node position"); + } + } + + return str; +} + +} // namespace mlspp diff --git a/src/davetest/dave.cpp b/src/davetest/dave.cpp new file mode 100644 index 0000000000..719dd1e06b --- /dev/null +++ b/src/davetest/dave.cpp @@ -0,0 +1,85 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#include +#include +#include + +std::string get_testdata_dir() { + char *env_var = getenv("TEST_DATA_DIR"); + return (env_var ? env_var : "../../testdata/"); +} + +std::vector load_test_audio() { + std::vector testaudio; + std::string dir = get_testdata_dir(); + std::ifstream input (dir + "Robot.pcm", std::ios::in|std::ios::binary|std::ios::ate); + if (input.is_open()) { + size_t testaudio_size = input.tellg(); + testaudio.resize(testaudio_size); + input.seekg(0, std::ios::beg); + input.read((char*)testaudio.data(), testaudio_size); + input.close(); + } + else { + std::cout << "ERROR: Can't load " + dir + "Robot.pcm\n"; + exit(1); + } + return testaudio; +} + +int main() { + + using namespace std::chrono_literals; + char* t = getenv("DPP_UNIT_TEST_TOKEN"); + if (t == nullptr || getenv("TEST_GUILD_ID") == nullptr || getenv("TEST_VC_ID") == nullptr) { + std::cerr << "Missing unit test environment. Set DPP_UNIT_TEST_TOKEN, TEST_GUILD_ID, and TEST_VC_ID\n"; + exit(1); + } + dpp::snowflake TEST_GUILD_ID(std::string(getenv("TEST_GUILD_ID"))); + dpp::snowflake TEST_VC_ID(std::string(getenv("TEST_VC_ID"))); + std::cout << "Test Guild ID: " << TEST_GUILD_ID << " Test VC ID: " << TEST_VC_ID << "\n\n"; + dpp::cluster dave_test(t, dpp::i_default_intents, 1, 0, 1, false, dpp::cache_policy_t{ dpp::cp_none, dpp::cp_none, dpp::cp_none, dpp::cp_none, dpp::cp_none }); + + dave_test.on_log([&](const dpp::log_t& log) { + std::cout << "[" << dpp::utility::current_date_time() << "] " << dpp::utility::loglevel(log.severity) << ": " << log.message << std::endl; + }); + + std::vector testaudio = load_test_audio(); + + dave_test.on_voice_ready([&](const dpp::voice_ready_t & event) { + dave_test.log(dpp::ll_info, "Voice channel ready, sending audio..."); + dpp::discord_voice_client* v = event.voice_client; + if (v && v->is_ready()) { + v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); + } + }); + + + dave_test.on_guild_create([&](const dpp::guild_create_t & event) { + if (event.created->id == TEST_GUILD_ID) { + dpp::discord_client* s = dave_test.get_shard(0); + bool muted = false, deaf = false, enable_dave = true; + s->connect_voice(TEST_GUILD_ID, TEST_VC_ID, muted, deaf, enable_dave); + } + }); + dave_test.start(false); +} diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 46aec35a5d..ff7345428c 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -154,6 +154,11 @@ void cluster::log(dpp::loglevel severity, const std::string &msg) const { dpp::log_t logmsg(nullptr, msg); logmsg.severity = severity; logmsg.message = msg; + size_t pos{0}; + while ((pos = logmsg.message.find(token, pos)) != std::string::npos) { + logmsg.message.replace(pos, token.length(), "*****"); + pos += 5; + } on_log.call(logmsg); } } diff --git a/src/dpp/dave/array_view.h b/src/dpp/dave/array_view.h new file mode 100755 index 0000000000..98b6025b34 --- /dev/null +++ b/src/dpp/dave/array_view.h @@ -0,0 +1,115 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include + +namespace dpp::dave { + +/** + * @brief This is a simple wrapper around a range of values, e.g. a vector or array. + * It is only constant if type T is constant. + * @tparam T Type in array or vector + */ +template class array_view { +public: + /** + * @brief Default constructor + */ + array_view() = default; + + /** + * @brief Construct array_view with data and size of data + * @param data data pointer to array + * @param size size of array + */ + array_view(T* data, size_t size) + : data_(data) + , size_(size) + { + } + + /** + * @brief Get size of view + * @return size + */ + size_t size() const { return size_; } + + /** + * @brief Get data of view from first element + * @return data + */ + T* data() const { return data_; } + + /** + * @brief Get start of view, first element + * @return first element + */ + T* begin() const { return data_; } + + /** + * @brief Get ending iterator of view, 1+last element + * @return end of view + */ + T* end() const { return data_ + size_; } + +private: + /** + * @brief array data + */ + T* data_ = nullptr; + /** + * @brief Array size + */ + size_t size_ = 0; +}; + +/** + * @brief Construct new array view from C style array + * @tparam T array member type + * @param data pointer to array + * @param size size of array + * @return array_view + */ +template +inline array_view make_array_view(T* data, size_t size) +{ + return array_view(data, size); +} + +/** + * @brief Construct new array view from vector + * @tparam T vector member type + * @param data vector + * @return array_view + */ +template +inline array_view make_array_view(std::vector& data) +{ + return array_view(data.data(), data.size()); +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/cipher_interface.cpp b/src/dpp/dave/cipher_interface.cpp new file mode 100755 index 0000000000..3dae2807cc --- /dev/null +++ b/src/dpp/dave/cipher_interface.cpp @@ -0,0 +1,38 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "cipher_interface.h" +#include "openssl_aead_cipher.h" +#include + +namespace dpp::dave { + +std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& encryptionKey) +{ + auto cipher = std::make_unique(cl, encryptionKey); + return cipher->is_valid() ? std::move(cipher) : nullptr; +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/cipher_interface.h b/src/dpp/dave/cipher_interface.h new file mode 100755 index 0000000000..35b849c279 --- /dev/null +++ b/src/dpp/dave/cipher_interface.h @@ -0,0 +1,103 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ + #pragma once + +#include + +#include "common.h" +#include "array_view.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief An array_view constant array of bytes + */ +using const_byte_view = array_view; + +/** + * @brief An array_view non-constant array of bytes + */ +using byte_view = array_view; + +/** + * @brief Represents a block cipher with AEAD used to encrypt or decrypt + * audio and video frames in the DAVE protocol. + */ +class cipher_interface { // NOLINT +public: + /** + * @brief Create cipher interface + * @param _creator Creating cluster + */ + cipher_interface(dpp::cluster& _creator) : creator(_creator) { }; + + /** + * @brief Default destructor + */ + virtual ~cipher_interface() = default; + + /** + * @brief Encrypt audio or video + * @param ciphertextBufferOut Output buffer of ciphertext + * @param plaintextBuffer Input buffer for plaintext + * @param nonceBuffer Input nonce/IV + * @param additionalData Additional data for GCM AEAD encryption + * @param tagBufferOut AEAD Tag for verification + * @return true if encryption succeeded, false if it failed + */ + virtual bool encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) = 0; + + /** + * @brief Decrypt audio or video + * @param plaintextBufferOut Output buffer for plaintext + * @param ciphertextBuffer Input buffer for ciphetext + * @param tagBuffer AEAD Tag for verification + * @param nonceBuffer Nonce/IV + * @param additionalData Additional data for GCM AEAD encryption + * @return true if decryption succeeded, false if it failed + */ + virtual bool decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) = 0; + +protected: + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +/** + * @brief Factory function to create new cipher interface of the best supported type for DAVE + * @param encryptionKey encryption key + * @return an instance of a class derived from cipher_interface + */ +std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& encryptionKey); + +} // namespace dpp::dave + diff --git a/src/dpp/dave/clock.h b/src/dpp/dave/clock.h new file mode 100755 index 0000000000..c8a2ab6872 --- /dev/null +++ b/src/dpp/dave/clock.h @@ -0,0 +1,78 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include + +namespace dpp::dave { + +/** + * @brief An interface for a wrapper around chrono clocks + */ +class clock_interface { +public: + /** + * @brief chrono steady clock + */ + using base_clock = std::chrono::steady_clock; + + /** + * @brief time point on a steady clock + */ + using time_point = base_clock::time_point; + + /** + * @brief duration on a steady clock + */ + using clock_duration = base_clock::duration; + + /** + * @brief Default destructor + */ + virtual ~clock_interface() = default; + + /** + * @brief Get current time + * @return current time + */ + virtual time_point now() const = 0; +}; + +/** + * @brief Chrono clock class + */ +class clock : public clock_interface { +public: + /** + * @brief Get current time + * @return current time + */ + time_point now() const override { + return base_clock::now(); + } +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/codec_utils.cpp b/src/dpp/dave/codec_utils.cpp new file mode 100755 index 0000000000..ea4269c050 --- /dev/null +++ b/src/dpp/dave/codec_utils.cpp @@ -0,0 +1,427 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "codec_utils.h" + +#include +#include +#include +#include "leb128.h" + +namespace dpp::dave::codec_utils { + +unencrypted_frame_header_size BytesCoveringH264PPS(const uint8_t* payload, const uint64_t sizeRemaining) +{ + // the payload starts with three exponential golomb encoded values + // (first_mb_in_slice, sps_id, pps_id) + // the depacketizer needs the pps_id unencrypted + // and the payload has RBSP encoding that we need to work around + + constexpr uint8_t kEmulationPreventionByte = 0x03; + + uint64_t payloadBitIndex = 0; + auto zeroBitCount = 0; + auto parsedExpGolombValues = 0; + + while (payloadBitIndex < sizeRemaining * 8 && parsedExpGolombValues < 3) { + auto bitIndex = payloadBitIndex % 8; + auto byteIndex = payloadBitIndex / 8; + auto payloadByte = payload[byteIndex]; + + // if we're starting a new byte + // check if this is an emulation prevention byte + // which we skip over + if (bitIndex == 0) { + if (byteIndex >= 2 && payloadByte == kEmulationPreventionByte && + payload[byteIndex - 1] == 0 && payload[byteIndex - 2] == 0) { + payloadBitIndex += 8; + continue; + } + } + + if ((payloadByte & (1 << (7 - bitIndex))) == 0) { + // still in the run of leading zero bits + ++zeroBitCount; + ++payloadBitIndex; + + if (zeroBitCount >= 32) { + throw dpp::length_exception("Unexpectedly large exponential golomb encoded value"); + } + } + else { + // we hit a one + // skip forward the number of bits dictated by the leading number of zeroes + parsedExpGolombValues += 1; + payloadBitIndex += 1 + zeroBitCount; + zeroBitCount = 0; + } + } + + // return the number of bytes that covers the last exp golomb encoded value + return (payloadBitIndex / 8) + 1; +} + +const uint8_t kH26XNaluLongStartCode[] = {0, 0, 0, 1}; +constexpr uint8_t kH26XNaluShortStartSequenceSize = 3; + +using IndexStartCodeSizePair = std::pair; + +std::optional FindNextH26XNaluIndex(const uint8_t* buffer, const size_t bufferSize, const size_t searchStartIndex = 0) +{ + constexpr uint8_t kH26XStartCodeHighestPossibleValue = 1; + constexpr uint8_t kH26XStartCodeEndByteValue = 1; + constexpr uint8_t kH26XStartCodeLeadingBytesValue = 0; + + if (bufferSize < kH26XNaluShortStartSequenceSize) { + return std::nullopt; + } + + // look for NAL unit 3 or 4 byte start code + for (size_t i = searchStartIndex; i < bufferSize - kH26XNaluShortStartSequenceSize;) { + if (buffer[i + 2] > kH26XStartCodeHighestPossibleValue) { + // third byte is not 0 or 1, can't be a start code + i += kH26XNaluShortStartSequenceSize; + } + else if (buffer[i + 2] == kH26XStartCodeEndByteValue) { + // third byte matches the start code end byte, might be a start code sequence + if (buffer[i + 1] == kH26XStartCodeLeadingBytesValue && + buffer[i] == kH26XStartCodeLeadingBytesValue) { + // confirmed start sequence {0, 0, 1} + auto nalUnitStartIndex = i + kH26XNaluShortStartSequenceSize; + + if (i >= 1 && buffer[i - 1] == kH26XStartCodeLeadingBytesValue) { + // 4 byte start code + return std::optional({nalUnitStartIndex, 4}); + } + else { + // 3 byte start code + return std::optional({nalUnitStartIndex, 3}); + } + } + + i += kH26XNaluShortStartSequenceSize; + } + else { + // third byte is 0, might be a four byte start code + ++i; + } + } + + return std::nullopt; +} + +bool process_frame_opus(outbound_frame_processor& processor, array_view frame) +{ + processor.add_encrypted_bytes(frame.data(), frame.size()); + return true; +} + +bool process_frame_vp8(outbound_frame_processor& processor, array_view frame) +{ + constexpr uint8_t kVP8KeyFrameUnencryptedBytes = 10; + constexpr uint8_t kVP8DeltaFrameUnencryptedBytes = 1; + + // parse the VP8 payload header to determine if it's a key frame + // https://datatracker.ietf.org/doc/html/rfc7741#section-4.3 + + // 0 1 2 3 4 5 6 7 + // +-+-+-+-+-+-+-+-+ + // |Size0|H| VER |P| + // +-+-+-+-+-+-+-+-+ + // P is an inverse key frame flag + + // if this is a key frame the depacketizer will read 10 bytes into the payload header + // if this is a delta frame the depacketizer only needs the first byte of the payload + // header (since that's where the key frame flag is) + + size_t unencryptedHeaderBytes = 0; + if ((frame.data()[0] & 0x01) == 0) { + unencryptedHeaderBytes = kVP8KeyFrameUnencryptedBytes; + } + else { + unencryptedHeaderBytes = kVP8DeltaFrameUnencryptedBytes; + } + + processor.add_unencrypted_bytes(frame.data(), unencryptedHeaderBytes); + processor.add_encrypted_bytes(frame.data() + unencryptedHeaderBytes, + frame.size() - unencryptedHeaderBytes); + return true; +} + +bool process_frame_vp9(outbound_frame_processor& processor, array_view frame) +{ + // payload descriptor is unencrypted in each packet + // and includes all information the depacketizer needs + processor.add_encrypted_bytes(frame.data(), frame.size()); + return true; +} + +bool process_frame_h264(outbound_frame_processor& processor, array_view frame) +{ + // minimize the amount of unencrypted header data for H264 depending on the NAL unit + // type from WebRTC, see: src/modules/rtp_rtcp/source/rtp_format_h264.cc + // src/common_video/h264/h264_common.cc + // src/modules/rtp_rtcp/source/video_rtp_depacketizer_h264.cc + + // constexpr uint8_t kH264SBit = 0x80; + constexpr uint8_t kH264NalHeaderTypeMask = 0x1F; + constexpr uint8_t kH264NalTypeSlice = 1; + constexpr uint8_t kH264NalTypeIdr = 5; + constexpr uint8_t kH264NalUnitHeaderSize = 1; + + // this frame can be packetized as a STAP-A or a FU-A + // so we need to look at the first NAL units to determine how many bytes + // the packetizer/depacketizer will need into the payload + if (frame.size() < kH26XNaluShortStartSequenceSize + kH264NalUnitHeaderSize) { + throw dpp::length_exception("H264 frame is too small to contain a NAL unit"); + } + + auto naluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size()); + while (naluIndexPair && naluIndexPair->first < frame.size() - 1) { + auto [nalUnitStartIndex, startCodeSize] = *naluIndexPair; + + auto nalType = frame.data()[nalUnitStartIndex] & kH264NalHeaderTypeMask; + + // copy the start code and then the NAL unit + + // Because WebRTC will convert them all start codes to 4-byte on the receiver side + // always write a long start code and then the NAL unit + processor.add_unencrypted_bytes(kH26XNaluLongStartCode, sizeof(kH26XNaluLongStartCode)); + + auto nextNaluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size(), nalUnitStartIndex); + auto nextNaluStart = nextNaluIndexPair.has_value() ? nextNaluIndexPair->first - nextNaluIndexPair->second : frame.size(); + + if (nalType == kH264NalTypeSlice || nalType == kH264NalTypeIdr) { + // once we've hit a slice or an IDR + // we just need to cover getting to the PPS ID + auto nalUnitPayloadStart = nalUnitStartIndex + kH264NalUnitHeaderSize; + auto nalUnitPPSBytes = BytesCoveringH264PPS(frame.data() + nalUnitPayloadStart, frame.size() - nalUnitPayloadStart); + + processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, kH264NalUnitHeaderSize + nalUnitPPSBytes); + processor.add_encrypted_bytes( + frame.data() + nalUnitStartIndex + kH264NalUnitHeaderSize + nalUnitPPSBytes, + nextNaluStart - nalUnitStartIndex - kH264NalUnitHeaderSize - nalUnitPPSBytes); + } + else { + // copy the whole NAL unit + processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, nextNaluStart - nalUnitStartIndex); + } + + naluIndexPair = nextNaluIndexPair; + } + + return true; +} + +bool process_frame_h265(outbound_frame_processor& processor, array_view frame) +{ + // minimize the amount of unencrypted header data for H265 depending on the NAL unit + // type from WebRTC, see: src/modules/rtp_rtcp/source/rtp_format_h265.cc + // src/common_video/h265/h265_common.cc + // src/modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc + + constexpr uint8_t kH265NalHeaderTypeMask = 0x7E; + constexpr uint8_t kH265NalTypeVclCutoff = 32; + constexpr uint8_t kH265NalUnitHeaderSize = 2; + + // this frame can be packetized as a STAP-A or a FU-A + // so we need to look at the first NAL units to determine how many bytes + // the packetizer/depacketizer will need into the payload + if (frame.size() < kH26XNaluShortStartSequenceSize + kH265NalUnitHeaderSize) { + throw dpp::length_exception("H265 frame is too small to contain a NAL unit"); + } + + // look for NAL unit 3 or 4 byte start code + auto naluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size()); + while (naluIndexPair && naluIndexPair->first < frame.size() - 1) { + auto [nalUnitStartIndex, startCodeSize] = *naluIndexPair; + + uint8_t nalType = (frame.data()[nalUnitStartIndex] & kH265NalHeaderTypeMask) >> 1; + + // copy the start code and then the NAL unit + + // Because WebRTC will convert them all start codes to 4-byte on the receiver side + // always write a long start code and then the NAL unit + processor.add_unencrypted_bytes(kH26XNaluLongStartCode, sizeof(kH26XNaluLongStartCode)); + + auto nextNaluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size(), nalUnitStartIndex); + auto nextNaluStart = nextNaluIndexPair.has_value() ? nextNaluIndexPair->first - nextNaluIndexPair->second : frame.size(); + + if (nalType < kH265NalTypeVclCutoff) { + // found a VCL NAL, encrypt the payload only + processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, kH265NalUnitHeaderSize); + processor.add_encrypted_bytes(frame.data() + nalUnitStartIndex + kH265NalUnitHeaderSize, nextNaluStart - nalUnitStartIndex - kH265NalUnitHeaderSize); + } else { + // copy the whole NAL unit + processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, nextNaluStart - nalUnitStartIndex); + } + + naluIndexPair = nextNaluIndexPair; + } + + return true; +} + +bool process_frame_av1(outbound_frame_processor& processor, array_view frame) +{ + constexpr uint8_t kAv1ObuHeaderHasExtensionMask = 0b0'0000'100; + constexpr uint8_t kAv1ObuHeaderHasSizeMask = 0b0'0000'010; + constexpr uint8_t kAv1ObuHeaderTypeMask = 0b0'1111'000; + constexpr uint8_t kObuTypeTemporalDelimiter = 2; + constexpr uint8_t kObuTypeTileList = 8; + constexpr uint8_t kObuTypePadding = 15; + constexpr uint8_t kObuExtensionSizeBytes = 1; + + size_t i = 0; + while (i < frame.size()) { + // Read the OBU header. + size_t obuHeaderIndex = i; + uint8_t obuHeader = frame.data()[obuHeaderIndex]; + i += sizeof(obuHeader); + + bool obuHasExtension = obuHeader & kAv1ObuHeaderHasExtensionMask; + bool obuHasSize = obuHeader & kAv1ObuHeaderHasSizeMask; + int obuType = (obuHeader & kAv1ObuHeaderTypeMask) >> 3; + + if (obuHasExtension) { + // Skip extension byte + i += kObuExtensionSizeBytes; + } + + if (i >= frame.size()) { + // Malformed frame + throw dpp::logic_exception("Malformed AV1 frame: header overflows frame"); + } + + size_t obuPayloadSize = 0; + if (obuHasSize) { + // Read payload size + const uint8_t* start = frame.data() + i; + const uint8_t* ptr = start; + obuPayloadSize = read_leb128(ptr, frame.end()); + if (!ptr) { + // Malformed frame + throw dpp::logic_exception("Malformed AV1 frame: invalid LEB128 size"); + } + i += ptr - start; + } + else { + // If the size is not present, the OBU extends to the end of the frame. + obuPayloadSize = frame.size() - i; + } + + const auto obuPayloadIndex = i; + + if (i + obuPayloadSize > frame.size()) { + // Malformed frame + throw dpp::logic_exception("Malformed AV1 frame: payload overflows frame"); + } + + i += obuPayloadSize; + + // We only copy the OBUs that will not get dropped by the packetizer + if (obuType != kObuTypeTemporalDelimiter && obuType != kObuTypeTileList && + obuType != kObuTypePadding) { + // if this is the last OBU, we may need to flip the "has size" bit + // which allows us to append necessary protocol data to the frame + bool rewrittenWithoutSize = false; + + if (i == frame.size() && obuHasSize) { + // Flip the "has size" bit + obuHeader &= ~kAv1ObuHeaderHasSizeMask; + rewrittenWithoutSize = true; + } + + // write the OBU header unencrypted + processor.add_unencrypted_bytes(&obuHeader, sizeof(obuHeader)); + if (obuHasExtension) { + // write the extension byte unencrypted + processor.add_unencrypted_bytes(frame.data() + obuHeaderIndex + sizeof(obuHeader), kObuExtensionSizeBytes); + } + + // write the OBU payload size unencrypted if it was present and we didn't rewrite + // without it + if (obuHasSize && !rewrittenWithoutSize) { + // The AMD AV1 encoder may pad LEB128 encoded sizes with a zero byte which the + // webrtc packetizer removes. To prevent the packetizer from changing the frame, + // we sanitize the size by re-writing it ourselves + uint8_t leb128Buffer[LEB128_MAX_SIZE]; + size_t additionalBytesToWrite = write_leb128(obuPayloadSize, leb128Buffer); + processor.add_unencrypted_bytes(leb128Buffer, additionalBytesToWrite); + } + + // add the OBU payload, encrypted + processor.add_encrypted_bytes(frame.data() + obuPayloadIndex, obuPayloadSize); + } + } + + return true; +} + +bool validate_encrypted_frame(outbound_frame_processor& processor, array_view frame) +{ + auto codec = processor.get_codec(); + if (codec != codec::cd_h264 && codec != codec::cd_h265) { + return true; + } + + constexpr size_t Padding = kH26XNaluShortStartSequenceSize - 1; + + const auto& unencryptedRanges = processor.get_unencrypted_ranges(); + + // H264 and H265 ciphertexts cannot contain a 3 or 4 byte start code {0, 0, 1} + // otherwise the packetizer gets confused + // and the frame we get on the decryption side will be shifted and fail to decrypt + size_t encryptedSectionStart = 0; + for (auto& range : unencryptedRanges) { + if (encryptedSectionStart == range.offset) { + encryptedSectionStart += range.size; + continue; + } + + auto start = encryptedSectionStart - std::min(encryptedSectionStart, size_t{Padding}); + auto end = std::min(range.offset + Padding, frame.size()); + if (FindNextH26XNaluIndex(frame.data() + start, end - start)) { + return false; + } + + encryptedSectionStart = range.offset + range.size; + } + + if (encryptedSectionStart == frame.size()) { + return true; + } + + auto start = encryptedSectionStart - std::min(encryptedSectionStart, size_t{Padding}); + auto end = frame.size(); + if (FindNextH26XNaluIndex(frame.data() + start, end - start)) { + return false; + } + + return true; +} + +} // namespace dpp::dave::codec_utils + + diff --git a/src/dpp/dave/codec_utils.h b/src/dpp/dave/codec_utils.h new file mode 100755 index 0000000000..b24ce31174 --- /dev/null +++ b/src/dpp/dave/codec_utils.h @@ -0,0 +1,96 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include "common.h" +#include "frame_processors.h" +#include "array_view.h" + +/** + * @brief Functions for processing specific frame types. + * Different types of audio/video frames have different rules for what parts of it + * must remain unencrypted to allow for routing and processing further up the chain. + */ +namespace dpp::dave::codec_utils { + +/** + * @brief process opus audio frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_opus(outbound_frame_processor & processor, array_view frame); + +/** + * @brief process VP8 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_vp8(outbound_frame_processor & processor, array_view frame); + +/** + * @brief process VP9 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_vp9(outbound_frame_processor & processor, array_view frame); + +/** + * @brief process H264 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_h264(outbound_frame_processor & processor, array_view frame); + +/** + * @brief process opus frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_h265(outbound_frame_processor & processor, array_view frame); + +/** + * @brief process opus frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ +bool process_frame_av1(outbound_frame_processor & processor, array_view frame); + +/** + * @brief Check if encrypted frame is valid + * @param processor outbound frame processor + * @param frame frame to validate + * @return true if frame could be validated + */ +bool validate_encrypted_frame(outbound_frame_processor& processor, array_view frame); + +} // namespace dpp::dave::codec_utils + + diff --git a/src/dpp/dave/common.h b/src/dpp/dave/common.h new file mode 100755 index 0000000000..62efe5bb60 --- /dev/null +++ b/src/dpp/dave/common.h @@ -0,0 +1,168 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "version.h" + +namespace mlspp::bytes_ns { + /** + * @brief bytes type + */ + struct bytes; +}; + +namespace dpp::dave { + +/** + * @brief Unencrypted frame header size + */ +using unencrypted_frame_header_size = uint16_t; + +/** + * @brief Truncated sync nonce + */ +using truncated_sync_nonce = uint32_t; + +/** + * @brief Magic marker + */ +using magic_marker = uint16_t; + +/** + * @brief Encryption key + */ +using encryption_key = ::mlspp::bytes_ns::bytes; + +/** + * @brief Transition ID + */ +using transition_id = uint16_t; + +/** + * @brief Supplemental bytes size + */ +using supplemental_bytes_size = uint8_t; + +/** + * @brief Media frame types + */ +enum media_type : uint8_t { media_audio, media_video }; + + +/** + * @brief Media codec types + */ +enum codec : uint8_t { cd_unknown, cd_opus, cd_vp8, cd_vp9, cd_h264, cd_h265, cd_av1 }; + +/** + * @brief Returned in std::variant when a message is hard-rejected and should trigger a reset + */ +struct failed_t {}; + +/** + * @brief Returned in std::variant when a message is soft-rejected and should not trigger a reset + */ +struct ignored_t {}; + +/** + * @briefMap of ID-key pairs. + * In process_commit, this lists IDs whose keys have been added, changed, or removed; + * an empty value value means a key was removed. + */ +using roster_map = std::map>; + +/** + * @brief Return type for functions producing RosterMap or hard or soft failures + */ +using roster_variant = std::variant; + +/** + * @brief Magic marker ID + */ +constexpr magic_marker MARKER_BYTES = 0xFAFA; + +/** + * Layout constants + */ +constexpr size_t AES_GCM_128_KEY_BYTES = 16; +constexpr size_t AES_GCM_128_NONCE_BYTES = 12; +constexpr size_t AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES = 4; +constexpr size_t AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET = AES_GCM_128_NONCE_BYTES - AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES; +constexpr size_t AES_GCM_127_TRUNCATED_TAG_BYTES = 8; +constexpr size_t RATCHET_GENERATION_BYTES = 1; +constexpr size_t RATCHET_GENERATION_SHIFT_BITS = 8 * (AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES - RATCHET_GENERATION_BYTES); +constexpr size_t SUPPLEMENTAL_BYTES = AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); +constexpr size_t TRANSFORM_PADDING_BYTES = 64; + +/** + * Timing constants + */ +constexpr auto DEFAULT_TRANSITION_EXPIRY = std::chrono::seconds(10); +constexpr auto CIPHER_EXPIRY = std::chrono::seconds(10); + +/** + * Behavior constants + */ +constexpr auto INIT_TRANSITION_ID = 0; +constexpr auto DISABLED_VERSION = 0; +constexpr auto MAX_GENERATION_GAP = 250; +constexpr auto MAX_MISSING_NONCES = 1000; +constexpr auto GENERATION_WRAP = 1 << (8 * RATCHET_GENERATION_BYTES); +constexpr auto MAX_FRAMES_PER_SECOND = 50 + 2 * 60; // 50 audio frames + 2 * 60fps video streams +constexpr std::array OPUS_SILENCE_PACKET = {0xF8, 0xFF, 0xFE}; + +// Utility routine for variant return types + +/** + * @brief Utility to get variant return types wrapped in an optional + * @tparam T type to get from variant + * @tparam V type for the optional + * @param variant variant to get from + * @return value retrieved or nullopt if not found + */ +template inline std::optional get_optional(V&& variant) +{ + if (auto map = std::get_if(&variant)) { + if constexpr (std::is_rvalue_reference_v) { + return std::move(*map); + } else { + return *map; + } + } + else { + return std::nullopt; + } +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/cryptor_manager.cpp b/src/dpp/dave/cryptor_manager.cpp new file mode 100755 index 0000000000..e5b6af321b --- /dev/null +++ b/src/dpp/dave/cryptor_manager.cpp @@ -0,0 +1,199 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "cryptor_manager.h" +#include +#include "key_ratchet.h" +#include +#include + +using namespace std::chrono_literals; + +namespace dpp::dave { + +key_generation compute_wrapped_generation(key_generation oldest, key_generation generation) +{ + // Assume generation is greater than or equal to oldest, this may be wrong in a few cases but + // will be caught by the max generation gap check. + auto remainder = oldest % GENERATION_WRAP; + auto factor = oldest / GENERATION_WRAP + (generation < remainder ? 1 : 0); + return factor * GENERATION_WRAP + generation; +} + +big_nonce compute_wrapped_big_nonce(key_generation generation, truncated_sync_nonce nonce) +{ + // Remove the generation bits from the nonce + auto maskedNonce = nonce & ((1 << RATCHET_GENERATION_SHIFT_BITS) - 1); + // Add the wrapped generation bits back in + return static_cast(generation) << RATCHET_GENERATION_SHIFT_BITS | maskedNonce; +} + +aead_cipher_manager::aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr keyRatchet) + : clock_(clock) + , keyRatchet_(std::move(keyRatchet)) + , ratchetCreation_(clock.now()) + , ratchetExpiry_(time_point::max()) + , creator(cl) +{ +} + +bool aead_cipher_manager::can_process_nonce(key_generation generation, truncated_sync_nonce nonce) const +{ + if (!newestProcessedNonce_) { + return true; + } + + auto bigNonce = compute_wrapped_big_nonce(generation, nonce); + return bigNonce > *newestProcessedNonce_ || + std::find(missingNonces_.rbegin(), missingNonces_.rend(), bigNonce) != missingNonces_.rend(); +} + +cipher_interface* aead_cipher_manager::get_cipher(key_generation generation) +{ + cleanup_expired_ciphers(); + + if (generation < oldestGeneration_) { + creator.log(dpp::ll_trace, "Received frame with old generation: " + std::to_string(generation) + ", oldest generation: " + std::to_string(oldestGeneration_)); + return nullptr; + } + + if (generation > newestGeneration_ + MAX_GENERATION_GAP) { + creator.log(dpp::ll_trace, "Received frame with future generation: " + std::to_string(generation) + ", newest generation: " + std::to_string(newestGeneration_)); + return nullptr; + } + + auto ratchetLifetimeSec = + std::chrono::duration_cast(clock_.now() - ratchetCreation_).count(); + auto maxLifetimeFrames = MAX_FRAMES_PER_SECOND * ratchetLifetimeSec; + auto maxLifetimeGenerations = maxLifetimeFrames >> RATCHET_GENERATION_SHIFT_BITS; + if (generation > maxLifetimeGenerations) { + creator.log(dpp::ll_debug, "Received frame with generation " + std::to_string(generation) + " beyond ratchet max lifetime generations: " + std::to_string(maxLifetimeGenerations) + ", ratchet lifetime: " + std::to_string(ratchetLifetimeSec) + "s"); + return nullptr; + } + + auto it = cryptors_.find(generation); + if (it == cryptors_.end()) { + // We don't have a cryptor for this generation, create one + std::tie(it, std::ignore) = cryptors_.emplace(generation, make_expiring_cipher(generation)); + } + + // Return a non-owning pointer to the cryptor + auto& [cryptor, expiry] = it->second; + return cryptor.get(); +} + +void aead_cipher_manager::report_cipher_success(key_generation generation, truncated_sync_nonce nonce) +{ + auto bigNonce = compute_wrapped_big_nonce(generation, nonce); + + // Add any missing nonces to the queue + if (!newestProcessedNonce_) { + newestProcessedNonce_ = bigNonce; + } + else if (bigNonce > *newestProcessedNonce_) { + auto oldestMissingNonce = bigNonce > MAX_MISSING_NONCES ? bigNonce - MAX_MISSING_NONCES : 0; + + while (!missingNonces_.empty() && missingNonces_.front() < oldestMissingNonce) { + missingNonces_.pop_front(); + } + + // If we're missing a lot, we don't want to add everything since newestProcessedNonce_ + auto missingRangeStart = std::max(oldestMissingNonce, *newestProcessedNonce_ + 1); + for (auto i = missingRangeStart; i < bigNonce; ++i) { + missingNonces_.push_back(i); + } + + // Update the newest processed nonce + newestProcessedNonce_ = bigNonce; + } + else { + auto it = std::find(missingNonces_.begin(), missingNonces_.end(), bigNonce); + if (it != missingNonces_.end()) { + missingNonces_.erase(it); + } + } + + if (generation <= newestGeneration_ || cryptors_.find(generation) == cryptors_.end()) { + return; + } + creator.log(dpp::ll_trace, "Reporting cryptor success, generation: " + std::to_string(generation)); + newestGeneration_ = generation; + + // Update the expiry time for all old cryptors + const auto expiryTime = clock_.now() + CIPHER_EXPIRY; + for (auto& [gen, cryptor] : cryptors_) { + if (gen < newestGeneration_) { + creator.log(dpp::ll_trace, "Updating expiry for cryptor, generation: " + std::to_string(gen)); + cryptor.expiry = std::min(cryptor.expiry, expiryTime); + } + } +} + +key_generation aead_cipher_manager::compute_wrapped_generation(key_generation generation) +{ + return ::dpp::dave::compute_wrapped_generation(oldestGeneration_, generation); +} + +aead_cipher_manager::expiring_cipher aead_cipher_manager::make_expiring_cipher(key_generation generation) +{ + // Get the new key from the ratchet + auto encryptionKey = keyRatchet_->get_key(generation); + auto expiryTime = time_point::max(); + + // If we got frames out of order, we might have to create a cryptor for an old generation + // In that case, create it with a non-infinite expiry time as we have already transitioned + // to a newer generation + if (generation < newestGeneration_) { + creator.log(dpp::ll_debug, "Creating cryptor for old generation: " + std::to_string(generation)); + expiryTime = clock_.now() + CIPHER_EXPIRY; + } + else { + creator.log(dpp::ll_debug, "Creating cryptor for new generation: " + std::to_string(generation)); + } + + return {create_cipher(creator, encryptionKey), expiryTime}; +} + +void aead_cipher_manager::cleanup_expired_ciphers() +{ + for (auto it = cryptors_.begin(); it != cryptors_.end();) { + auto& [generation, cryptor] = *it; + + bool expired = cryptor.expiry < clock_.now(); + if (expired) { + creator.log(dpp::ll_trace, "Removing expired cryptor, generation: " + std::to_string(generation)); + } + + it = expired ? cryptors_.erase(it) : ++it; + } + + while (oldestGeneration_ < newestGeneration_ && cryptors_.find(oldestGeneration_) == cryptors_.end()) { + creator.log(dpp::ll_trace, "Deleting key for old generation: " + std::to_string(oldestGeneration_)); + keyRatchet_->delete_key(oldestGeneration_); + ++oldestGeneration_; + } +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/cryptor_manager.h b/src/dpp/dave/cryptor_manager.h new file mode 100755 index 0000000000..774e87f23e --- /dev/null +++ b/src/dpp/dave/cryptor_manager.h @@ -0,0 +1,172 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include + +#include "cipher_interface.h" +#include "key_ratchet.h" +#include "common.h" +#include "clock.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief Compute wrapped generation for key + * @param oldest oldest key generation + * @param generation key generation + * @return wrapped computed generation + */ +key_generation compute_wrapped_generation(key_generation oldest, key_generation generation); + +/** + * @brief A big nonce (64 bits) + */ +using big_nonce = uint64_t; + +/** + * @brief Compute wrapped big nonce + * @param generation generation + * @param nonce truncated sync nonce + * @return big nonce (64 bits) + */ +big_nonce compute_wrapped_big_nonce(key_generation generation, truncated_sync_nonce nonce); + +/** + * @brief A manager to handle whichever cipher is best for the current version of DAVE + * + * This will currently instantiate an AES 128 GCM AEAD cipher. + */ +class aead_cipher_manager { +public: + /** + * @brief Chrono time point + */ + using time_point = typename clock_interface::time_point; + + /** + * @brief Constructor + * @param cl Creating cluster + * @param clock chrono clock + * @param keyRatchet key ratchet for cipher + */ + aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr keyRatchet); + + /** + * @brief Update cipher expiry + * @param expiry expiry time + */ + void update_expiry(time_point expiry) { + ratchetExpiry_ = expiry; + } + + /** + * @brief True if cipher has expired + * @return true if expired + */ + bool is_expired() const { + return clock_.now() > ratchetExpiry_; + } + + /** + * @brief True if nonce can be processed for generation + * @param generation key generation + * @param nonce nonce/IV + * @return true if can be processed + */ + bool can_process_nonce(key_generation generation, truncated_sync_nonce nonce) const; + + /** + * Compute wrapped generation for key + * @param generation key generation + * @return key generation + */ + key_generation compute_wrapped_generation(key_generation generation); + + cipher_interface* get_cipher(key_generation generation); + + /** + * @brief Updates the expiry time for all old ciphers + * @param generation key generation + * @param nonce nonce/IV + */ + void report_cipher_success(key_generation generation, truncated_sync_nonce nonce); + +private: + /** + * @brief Cipher with an expiry date/time + */ + struct expiring_cipher { + /** + * @brief Cipher + */ + std::unique_ptr cryptor; + + /** + * @brief Expiry time + */ + time_point expiry; + }; + + /** + * Create a cipher with an expiry time + * @param generation key generation + * @return expiring cipher + */ + expiring_cipher make_expiring_cipher(key_generation generation); + + /** + * @brief Clean up old expired ciphers + */ + void cleanup_expired_ciphers(); + + const clock_interface& clock_; + std::unique_ptr keyRatchet_; + std::unordered_map cryptors_; + + time_point ratchetCreation_; + time_point ratchetExpiry_; + key_generation oldestGeneration_{0}; + key_generation newestGeneration_{0}; + + std::optional newestProcessedNonce_; + std::deque missingNonces_; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; + +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/decryptor.cpp b/src/dpp/dave/decryptor.cpp new file mode 100755 index 0000000000..e2fa7272be --- /dev/null +++ b/src/dpp/dave/decryptor.cpp @@ -0,0 +1,233 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "decryptor.h" +#include +#include +#include +#include "common.h" +#include "leb128.h" +#include "scope_exit.h" + +using namespace std::chrono_literals; + +namespace dpp::dave { + +constexpr auto kStatsInterval = 10s; + +void decryptor::transition_to_key_ratchet(std::unique_ptr keyRatchet, + duration transitionExpiry) +{ + if (keyRatchet) { + creator.log(dpp::ll_trace, "Transitioning to new key ratchet, expiry: " + std::to_string(transitionExpiry.count())); + } + + // Update the expiry time for all existing cryptor managers + update_cryptor_manager_expiry(transitionExpiry); + + if (keyRatchet) { + cryptorManagers_.emplace_back(creator, clock_, std::move(keyRatchet)); + } +} + +void decryptor::transition_to_passthrough_mode(bool passthroughMode, duration transitionExpiry) +{ + if (passthroughMode) { + allowPassThroughUntil_ = time_point::max(); + } + else { + // Update the pass through mode expiry + auto maxExpiry = clock_.now() + transitionExpiry; + allowPassThroughUntil_ = std::min(allowPassThroughUntil_, maxExpiry); + } +} + +size_t decryptor::decrypt(media_type mediaType, + array_view encryptedFrame, + array_view frame) +{ + if (mediaType != media_audio && mediaType != media_video) { + creator.log(dpp::ll_trace, "decrypt failed, invalid media type: " + std::to_string(static_cast(mediaType))); + return 0; + } + + auto start = clock_.now(); + + auto localFrame = get_or_create_frame_processor(); + scope_exit cleanup([&] { return_frame_processor(std::move(localFrame)); }); + + // Skip decrypting for silence frames + if (mediaType == media_audio && encryptedFrame.size() == OPUS_SILENCE_PACKET.size() && + std::memcmp(encryptedFrame.data(), OPUS_SILENCE_PACKET.data(), OPUS_SILENCE_PACKET.size()) == 0) { + creator.log(dpp::ll_trace, "decrypt skipping silence of size: " + std::to_string(encryptedFrame.size())); + if (encryptedFrame.data() != frame.data()) { + std::memcpy(frame.data(), encryptedFrame.data(), encryptedFrame.size()); + } + return encryptedFrame.size(); + } + + // Remove any expired cryptor manager + cleanup_expired_cryptor_managers(); + + // Process the incoming frame + // This will check whether it looks like a valid encrypted frame + // and if so it will parse it into its different components + localFrame->parse_frame(encryptedFrame); + + // If the frame is not encrypted and we can pass it through, do it + bool canUsePassThrough = allowPassThroughUntil_ > start; + if (!localFrame->is_encrypted() && canUsePassThrough) { + if (encryptedFrame.data() != frame.data()) { + std::memcpy(frame.data(), encryptedFrame.data(), encryptedFrame.size()); + } + stats_[mediaType].passthroughs++; + return encryptedFrame.size(); + } + + // If the frame is not encrypted and we can't pass it through, fail + if (!localFrame->is_encrypted()) { + creator.log(dpp::ll_warning, "decrypt failed, frame is not encrypted and pass through is disabled"); + stats_[mediaType].decrypt_failure++; + return 0; + } + + // Try and decrypt with each valid cryptor + // reverse iterate to try the newest cryptors first + bool success = false; + for (auto it = cryptorManagers_.rbegin(); it != cryptorManagers_.rend(); ++it) { + auto& cryptorManager = *it; + success = decrypt_impl(cryptorManager, mediaType, *localFrame, frame); + if (success) { + break; + } + } + + size_t bytesWritten = 0; + if (success) { + stats_[mediaType].decrypt_success++; + bytesWritten = localFrame->reconstruct_frame(frame); + } + else { + stats_[mediaType].decrypt_failure++; + creator.log(dpp::ll_warning, "decrypt failed, no valid cryptor found, type: " + std::string(mediaType ? "video" : "audio") + + ", encrypted frame size: " + std::to_string(encryptedFrame.size()) + + ", plaintext frame size: " + std::to_string(frame.size()) + + ", number of cryptor managers: " + std::to_string(cryptorManagers_.size()) + + ", pass through enabled: " + std::string(canUsePassThrough ? "yes" : "no") + ); + } + + auto end = clock_.now(); + stats_[mediaType].decrypt_duration += std::chrono::duration_cast(end - start).count(); + + return bytesWritten; +} + +bool decryptor::decrypt_impl(aead_cipher_manager& cipher_manager, + media_type mediaType, + inbound_frame_processor& encryptedFrame, + array_view frame) +{ + auto tag = encryptedFrame.get_tag(); + auto truncatedNonce = encryptedFrame.get_truncated_nonce(); + + auto authenticatedData = encryptedFrame.get_authenticated_data(); + auto ciphertext = encryptedFrame.get_ciphertext(); + auto plaintext = encryptedFrame.get_plaintext(); + + // expand the truncated nonce to the full sized one needed for decryption + auto nonceBuffer = std::array(); + memcpy(nonceBuffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, + &truncatedNonce, + AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); + + auto nonceBufferView = make_array_view(nonceBuffer.data(), nonceBuffer.size()); + + auto generation = + cipher_manager.compute_wrapped_generation(truncatedNonce >> RATCHET_GENERATION_SHIFT_BITS); + + if (!cipher_manager.can_process_nonce(generation, truncatedNonce)) { + creator.log(dpp::ll_trace, "decrypt failed, cannot process nonce"); + return false; + } + + // Get the cryptor for this generation + cipher_interface* cipher = cipher_manager.get_cipher(generation); + + if (cipher == nullptr) { + creator.log(dpp::ll_warning, "decrypt failed, no cryptor found for generation: " + std::to_string(generation)); + return false; + } + + // perform the decryption + bool success = cipher->decrypt(plaintext, ciphertext, tag, nonceBufferView, authenticatedData); + stats_[mediaType].decrypt_attempts++; + + if (success) { + cipher_manager.report_cipher_success(generation, truncatedNonce); + } + + return success; +} + +size_t decryptor::get_max_plaintext_byte_size(media_type mediaType, size_t encryptedFrameSize) +{ + return encryptedFrameSize; +} + +void decryptor::update_cryptor_manager_expiry(duration expiry) +{ + auto maxExpiryTime = clock_.now() + expiry; + for (auto& cryptorManager : cryptorManagers_) { + cryptorManager.update_expiry(maxExpiryTime); + } +} + +void decryptor::cleanup_expired_cryptor_managers() +{ + while (!cryptorManagers_.empty() && cryptorManagers_.front().is_expired()) { + creator.log(dpp::ll_trace, "Removing expired cryptor manager"); + cryptorManagers_.pop_front(); + } +} + +std::unique_ptr decryptor::get_or_create_frame_processor() +{ + std::lock_guard lock(frameProcessorsMutex_); + if (frameProcessors_.empty()) { + return std::make_unique(creator); + } + auto frameProcessor = std::move(frameProcessors_.back()); + frameProcessors_.pop_back(); + return frameProcessor; +} + +void decryptor::return_frame_processor(std::unique_ptr frameProcessor) +{ + std::lock_guard lock(frameProcessorsMutex_); + frameProcessors_.push_back(std::move(frameProcessor)); +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/decryptor.h b/src/dpp/dave/decryptor.h new file mode 100755 index 0000000000..804c41c826 --- /dev/null +++ b/src/dpp/dave/decryptor.h @@ -0,0 +1,200 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "codec_utils.h" +#include "common.h" +#include "cipher_interface.h" +#include "cryptor_manager.h" +#include "frame_processors.h" +#include "version.h" +#include "clock.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +class key_ratchet_interface; + +/** + * @brief Decryption stats + */ +struct decryption_stats { + /** + * @brief Number of passthroughs + */ + uint64_t passthroughs = 0; + /** + * @brief Number of decryption successes + */ + uint64_t decrypt_success = 0; + /** + * @brief Number of decryption failures + */ + uint64_t decrypt_failure = 0; + /** + * @brief Total encryption duration + */ + uint64_t decrypt_duration = 0; + /** + * @brief Number of decryption attempts + */ + uint64_t decrypt_attempts = 0; +}; + +/** + * @brief Decryptor, decrypts encrypted frames + */ +class decryptor { +public: + /** + * @brief Constructor + * @param cl Creator + */ + decryptor(dpp::cluster& cl) : creator(cl) { }; + + /** + * @brief Chrono duration + */ + using duration = std::chrono::seconds; + + /** + * @brief Set a new key ratchet for a decryptor. These are derived during welcome/commit + * of the session. Once you have a key ratchet, you can derive the key, and decrypt that + * user's audio/video. + * + * @param keyRatchet Key ratchet + * @param transitionExpiry Transition expiry. Old keys last this long before being withdrawn + * in preference of this new one. + */ + void transition_to_key_ratchet(std::unique_ptr keyRatchet, + duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + + /** + * @brief Transition to passthrough mode + * + * Passthrough mode occurs when a non-DAVE user connects to the VC. + * + * @param passthroughMode True to enable passthrough mode + * @param transitionExpiry Expiry for the transition + */ + void transition_to_passthrough_mode(bool passthroughMode, + duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + + /** + * @brief Decrypt a frame + * + * @param mediaType type of media, audio or video + * @param encryptedFrame encrypted frame bytes + * @param frame plaintext output + * @return size of decrypted frame, or 0 if failure + */ + size_t decrypt(media_type mediaType, + array_view encryptedFrame, + array_view frame); + + /** + * @brief Get maximum possible decrypted size of frame from an encrypted frame + * @param mediaType type of media + * @param encryptedFrameSize encrypted frame size + * @return size of plaintext buffer required + */ + size_t get_max_plaintext_byte_size(media_type mediaType, size_t encryptedFrameSize); + + /** + * @brief Get decryption stats + * @param mediaType media type, audio or video + * @return decryption stats + */ + decryption_stats get_stats(media_type mediaType) const { return stats_[mediaType]; } + +private: + /** + * @brief Chrono time point + */ + using time_point = clock_interface::time_point; + + /** + * @brief Decryption implementation + * + * @param cipher_manager cipher manager + * @param mediaType media time, audio or video + * @param encryptedFrame encrypted frame data + * @param frame decrypted frame data + * @return True if decryption succeeded + */ + bool decrypt_impl(aead_cipher_manager& cipher_manager, media_type mediaType, inbound_frame_processor& encryptedFrame, array_view frame); + + /** + * @brief Update expiry for an instance of the manager + * @param expiry expiry duration + */ + void update_cryptor_manager_expiry(duration expiry); + + /** + * @brief Clean up expired cryptor managers + */ + void cleanup_expired_cryptor_managers(); + + /** + * @brief Get frame procesor, or create a new one + * @return frame processor + */ + std::unique_ptr get_or_create_frame_processor(); + + /** + * Return frame processor + * @param frameProcessor frame processor + */ + void return_frame_processor(std::unique_ptr frameProcessor); + + clock clock_; + std::deque cryptorManagers_; + + std::mutex frameProcessorsMutex_; + std::vector> frameProcessors_; + + time_point allowPassThroughUntil_{time_point::min()}; + + time_point lastStatsTime_{time_point::min()}; + std::array stats_; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp new file mode 100755 index 0000000000..b169662754 --- /dev/null +++ b/src/dpp/dave/encryptor.cpp @@ -0,0 +1,299 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "encryptor.h" +#include +#include +#include +#include +#include +#include "common.h" +#include "cryptor_manager.h" +#include "codec_utils.h" +#include "array_view.h" +#include "leb128.h" +#include "scope_exit.h" + +using namespace std::chrono_literals; + +namespace dpp::dave { + +constexpr auto kStatsInterval = 10s; + +void encryptor::set_key_ratchet(std::unique_ptr keyRatchet) +{ + std::lock_guard lock(keyGenMutex_); + keyRatchet_ = std::move(keyRatchet); + cryptor_ = nullptr; + currentKeyGeneration_ = 0; + truncatedNonce_ = 0; +} + +void encryptor::set_passthrough_mode(bool passthroughMode) +{ + passthroughMode_ = passthroughMode; + update_current_protocol_version(passthroughMode ? 0 : max_protocol_version()); +} + +encryptor::result_code encryptor::encrypt(media_type mediaType, + uint32_t ssrc, + array_view frame, + array_view encryptedFrame, + size_t* bytesWritten) +{ + if (mediaType != media_audio && mediaType != media_video) { + creator.log(dpp::ll_warning, "encrypt failed, invalid media type: " + std::to_string(static_cast(mediaType))); + return result_code::rc_encryption_failure; + } + + if (passthroughMode_) { + // Pass frame through without encrypting + std::memcpy(encryptedFrame.data(), frame.data(), frame.size()); + *bytesWritten = frame.size(); + stats_[mediaType].passthroughs++; + return result_code::rc_success; + } + + { + std::lock_guard lock(keyGenMutex_); + if (!keyRatchet_) { + stats_[mediaType].encrypt_failure++; + return result_code::rc_encryption_failure; + } + } + + auto start = std::chrono::steady_clock::now(); + auto result = result_code::rc_success; + + // write the codec identifier + auto codec = codec_for_ssrc(ssrc); + + auto frameProcessor = get_or_create_frame_processor(); + scope_exit cleanup([&] { return_frame_processor(std::move(frameProcessor)); }); + + frameProcessor->process_frame(frame, codec); + + const auto& unencryptedBytes = frameProcessor->get_unencrypted_bytes(); + const auto& encryptedBytes = frameProcessor->get_encrypted_bytes(); + auto& ciphertextBytes = frameProcessor->get_ciphertext_bytes(); + + const auto& unencryptedRanges = frameProcessor->get_unencrypted_ranges(); + auto unencryptedRangesSize = unencrypted_ranges_size(unencryptedRanges); + + auto additionalData = make_array_view(unencryptedBytes.data(), unencryptedBytes.size()); + auto plaintextBuffer = make_array_view(encryptedBytes.data(), encryptedBytes.size()); + auto ciphertextBuffer = make_array_view(ciphertextBytes.data(), ciphertextBytes.size()); + + auto frameSize = encryptedBytes.size() + unencryptedBytes.size(); + auto tagBuffer = make_array_view(encryptedFrame.data() + frameSize, AES_GCM_127_TRUNCATED_TAG_BYTES); + + auto nonceBuffer = std::array(); + auto nonceBufferView = make_array_view(nonceBuffer.data(), nonceBuffer.size()); + + constexpr auto MAX_CIPHERTEXT_VALIDATION_RETRIES = 10; + + // some codecs (e.g. H26X) have packetizers that cannot handle specific byte sequences + // so we attempt up to MAX_CIPHERTEXT_VALIDATION_RETRIES to encrypt the frame + // calling into codec utils to validate the ciphertext + supplemental section + // and re-rolling the truncated nonce if it fails + + // the nonce increment will definitely change the ciphertext and the tag + // incrementing the nonce will also change the appropriate bytes + // in the tail end of the nonce + // which can remove start codes from the last 1 or 2 bytes of the nonce + // and the two bytes of the unencrypted header bytes + for (auto attempt = 1; attempt <= MAX_CIPHERTEXT_VALIDATION_RETRIES; ++attempt) { + auto [cryptor, truncatedNonce] = get_next_cryptor_and_nonce(); + + if (!cryptor) { + result = result_code::rc_encryption_failure; + break; + } + + // write the truncated nonce to our temporary full nonce array + // (since the encryption call expects a full size nonce) + std::memcpy(nonceBuffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, + &truncatedNonce, + AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); + + // encrypt the plaintext, adding the unencrypted header to the tag + bool success = cryptor->encrypt( + ciphertextBuffer, plaintextBuffer, nonceBufferView, additionalData, tagBuffer); + + stats_[mediaType].encrypt_attempts++; + stats_[mediaType].encrypt_max_attempts = + std::max(stats_[mediaType].encrypt_max_attempts, (uint64_t)attempt); + + if (!success) { + result = result_code::rc_encryption_failure; + break; + } + + auto reconstructedFrameSize = frameProcessor->reconstruct_frame(encryptedFrame); + + auto nonceSize = leb128_size(truncatedNonce); + + auto truncatedNonceBuffer = make_array_view(tagBuffer.end(), nonceSize); + auto unencryptedRangesBuffer = + make_array_view(truncatedNonceBuffer.end(), unencryptedRangesSize); + auto supplementalBytesBuffer = + make_array_view(unencryptedRangesBuffer.end(), sizeof(supplemental_bytes_size)); + auto markerBytesBuffer = make_array_view(supplementalBytesBuffer.end(), sizeof(magic_marker)); + + // write the nonce + auto res = write_leb128(truncatedNonce, truncatedNonceBuffer.begin()); + if (res != nonceSize) { + result = result_code::rc_encryption_failure; + break; + } + + // write the unencrypted ranges + res = serialize_unencrypted_ranges( + unencryptedRanges, unencryptedRangesBuffer.begin(), unencryptedRangesBuffer.size()); + if (res != unencryptedRangesSize) { + result = result_code::rc_encryption_failure; + break; + } + + // write the supplemental bytes size + supplemental_bytes_size supplementalBytes = + SUPPLEMENTAL_BYTES + nonceSize + unencryptedRangesSize; + std::memcpy(supplementalBytesBuffer.data(), &supplementalBytes, sizeof(supplemental_bytes_size)); + + // write the marker bytes, ends the frame + std::memcpy(markerBytesBuffer.data(), &MARKER_BYTES, sizeof(magic_marker)); + + auto encryptedFrameBytes = reconstructedFrameSize + AES_GCM_127_TRUNCATED_TAG_BYTES + + nonceSize + unencryptedRangesSize + sizeof(supplemental_bytes_size) + sizeof(magic_marker); + + if (codec_utils::validate_encrypted_frame( + *frameProcessor, make_array_view(encryptedFrame.data(), encryptedFrameBytes))) { + *bytesWritten = encryptedFrameBytes; + break; + } + else if (attempt >= MAX_CIPHERTEXT_VALIDATION_RETRIES) { + result = result_code::rc_encryption_failure; + break; + } + } + + auto now = std::chrono::steady_clock::now(); + stats_[mediaType].encrypt_duration += + std::chrono::duration_cast(now - start).count(); + if (result == result_code::rc_success) { + stats_[mediaType].encrypt_success++; + } + else { + stats_[mediaType].encrypt_failure++; + } + + return result; +} + +size_t encryptor::get_max_ciphertext_byte_size(media_type mediaType, size_t frameSize) +{ + return frameSize + SUPPLEMENTAL_BYTES + TRANSFORM_PADDING_BYTES; +} + +void encryptor::assign_ssrc_to_codec(uint32_t ssrc, codec codecType) +{ + auto existingCodecIt = std::find_if( + ssrcCodecPairs_.begin(), ssrcCodecPairs_.end(), [ssrc](const SsrcCodecPair& pair) { + return pair.first == ssrc; + }); + + if (existingCodecIt == ssrcCodecPairs_.end()) { + ssrcCodecPairs_.emplace_back(ssrc, codecType); + } + else { + existingCodecIt->second = codecType; + } +} + +codec encryptor::codec_for_ssrc(uint32_t ssrc) +{ + auto existingCodecIt = std::find_if( + ssrcCodecPairs_.begin(), ssrcCodecPairs_.end(), [ssrc](const SsrcCodecPair& pair) { + return pair.first == ssrc; + }); + + if (existingCodecIt != ssrcCodecPairs_.end()) { + return existingCodecIt->second; + } + else { + return codec::cd_opus; + } +} + +std::unique_ptr encryptor::get_or_create_frame_processor() +{ + std::lock_guard lock(frameProcessorsMutex_); + if (frameProcessors_.empty()) { + return std::make_unique(creator); + } + auto frameProcessor = std::move(frameProcessors_.back()); + frameProcessors_.pop_back(); + return frameProcessor; +} + +void encryptor::return_frame_processor(std::unique_ptr frameProcessor) +{ + std::lock_guard lock(frameProcessorsMutex_); + frameProcessors_.push_back(std::move(frameProcessor)); +} + +encryptor::cryptor_and_nonce encryptor::get_next_cryptor_and_nonce() +{ + std::lock_guard lock(keyGenMutex_); + if (!keyRatchet_) { + return {nullptr, 0}; + } + + auto generation = compute_wrapped_generation(currentKeyGeneration_, + ++truncatedNonce_ >> RATCHET_GENERATION_SHIFT_BITS); + + if (generation != currentKeyGeneration_ || !cryptor_) { + currentKeyGeneration_ = generation; + + auto encryptionKey = keyRatchet_->get_key(currentKeyGeneration_); + cryptor_ = create_cipher(creator, encryptionKey); + } + + return {cryptor_, truncatedNonce_}; +} + +void encryptor::update_current_protocol_version(protocol_version version) +{ + if (version == currentProtocolVersion_) { + return; + } + + currentProtocolVersion_ = version; + if (protocolVersionChangedCallback_) { + protocolVersionChangedCallback_(); + } +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/encryptor.h b/src/dpp/dave/encryptor.h new file mode 100755 index 0000000000..978238d744 --- /dev/null +++ b/src/dpp/dave/encryptor.h @@ -0,0 +1,254 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "codec_utils.h" +#include "common.h" +#include "cipher_interface.h" +#include "key_ratchet.h" +#include "frame_processors.h" +#include "version.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief Encryption stats + */ +struct encryption_stats { + /** + * @brief Number of passthrough packets + */ + uint64_t passthroughs = 0; + /** + * @brief Number of encryption successes + */ + uint64_t encrypt_success = 0; + /** + * @brief Number of encryption failures + */ + uint64_t encrypt_failure = 0; + /** + * @brief Duration encrypted + */ + uint64_t encrypt_duration = 0; + /** + * @brief Number of encryption atempts + */ + uint64_t encrypt_attempts = 0; + /** + * @brief Maximum attempts at encryption + */ + uint64_t encrypt_max_attempts = 0; +}; + +class encryptor { +public: + /** + * @brief Constructor + * @param cl Creator + */ + encryptor(dpp::cluster& cl) : creator(cl) { }; + + /** + * @brief Return codes for encryptor::encrypt + */ + enum result_code : uint8_t { + /** + * @brief Successful encryption + */ + rc_success, + /** + * @brief Encryption failure + */ + rc_encryption_failure, + }; + + /** + * @brief Set key ratchet for encryptor, this should be the bot's ratchet. + * @param keyRatchet Bot's key ratchet + */ + void set_key_ratchet(std::unique_ptr keyRatchet); + + /** + * @brief Set encryption to passthrough mode + * @param passthroughMode true to enable passthrough mode, false to disable + */ + void set_passthrough_mode(bool passthroughMode); + + /** + * @brief True if key ratchet assigned + * @return key ratchet is assigned + */ + bool has_key_ratchet() const { + return keyRatchet_ != nullptr; + } + + /** + * @brief True if is in passthrough mode + * @return is in passthrough mode + */ + bool is_passthrough_mode() const { + return passthroughMode_; + } + + /** + * @brief Assign SSRC to codec + * @note This is unused - all SSRC are assumed to be OPUS for bots at present. + * @param ssrc RTP SSRC + * @param codecType Codec type + */ + void assign_ssrc_to_codec(uint32_t ssrc, codec codecType); + + /** + * @brief Get codec for RTP SSRC + * @note This is unused - all SSRC are assumed to be OPUS for bots at present. + * @param ssrc RTP SSRC + * @return always returns OPUS as bots can only send/receive audio at present + */ + codec codec_for_ssrc(uint32_t ssrc); + + /** + * @brief Encrypt plaintext opus frames + * @param mediaType media type, should always be audio + * @param ssrc RTP SSRC + * @param frame Frame plaintext + * @param encryptedFrame Encrypted frame + * @param bytesWritten Number of bytes written to the encrypted buffer + * @return Status code for encryption + */ + encryptor::result_code encrypt(media_type mediaType, + uint32_t ssrc, + array_view frame, + array_view encryptedFrame, + size_t* bytesWritten); + + /** + * @brief Get maximum possible ciphertext size for a plaintext buffer + * @param mediaType media type, should always be audio for bots + * @param frameSize frame size of plaintext buffer + * @return size of ciphertext buffer to allocate + */ + size_t get_max_ciphertext_byte_size(media_type mediaType, size_t frameSize); + + /** + * @brief Get encryption stats + * @param mediaType media type + * @return encryption stats + */ + encryption_stats get_stats(media_type mediaType) const { + return stats_[mediaType]; + } + + /** + * @brief Protocol version changed callback + */ + using protocol_version_changed_callback = std::function; + + /** + * @brief Set protocol version changed callback + * @param callback Callback to set + */ + void set_protocol_version_changed_callback(protocol_version_changed_callback callback) { + protocolVersionChangedCallback_ = std::move(callback); + } + + /** + * @brief Get protocol version + * @return protocol version + */ + protocol_version get_protocol_version() const { + return currentProtocolVersion_; + } + +private: + /** + * @brief Get the current frame processor or create a new one + * @return Frame processor + */ + std::unique_ptr get_or_create_frame_processor(); + + /** + * @brief Return frame processor + * @param frameProcessor frame processor + */ + void return_frame_processor(std::unique_ptr frameProcessor); + + /** + * @brief Pair of cryptor and nonce pointers + */ + using cryptor_and_nonce = std::pair, truncated_sync_nonce>; + + /** + * @brief Get cryptor and nonce + * @return cryptor and nonce + */ + cryptor_and_nonce get_next_cryptor_and_nonce(); + + /** + * @brief Change protocol version + * @param version new protocol version + */ + void update_current_protocol_version(protocol_version version); + + std::atomic_bool passthroughMode_{false}; + + std::mutex keyGenMutex_; + std::unique_ptr keyRatchet_; + std::shared_ptr cryptor_; + key_generation currentKeyGeneration_{0}; + truncated_sync_nonce truncatedNonce_{0}; + + std::mutex frameProcessorsMutex_; + std::vector> frameProcessors_; + + using SsrcCodecPair = std::pair; + std::vector ssrcCodecPairs_; + + using TimePoint = std::chrono::time_point; + TimePoint lastStatsTime_{TimePoint::min()}; + std::array stats_; + + protocol_version_changed_callback protocolVersionChangedCallback_; + protocol_version currentProtocolVersion_{max_protocol_version()}; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/frame_processors.cpp b/src/dpp/dave/frame_processors.cpp new file mode 100755 index 0000000000..9cd8b8c4a6 --- /dev/null +++ b/src/dpp/dave/frame_processors.cpp @@ -0,0 +1,388 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "frame_processors.h" +#include +#include +#include +#include +#include +#include +#include "codec_utils.h" +#include "array_view.h" +#include "leb128.h" + +#if defined(_MSC_VER) + #include +#endif + +namespace dpp::dave { + +std::pair OverflowAdd(size_t a, size_t b) +{ + size_t res; +#if defined(_MSC_VER) && defined(_M_X64) + bool didOverflow = _addcarry_u64(0, a, b, &res); +#elif defined(_MSC_VER) && defined(_M_IX86) + bool didOverflow = _addcarry_u32(0, a, b, &res); +#else + bool didOverflow = __builtin_add_overflow(a, b, &res); +#endif + return {didOverflow, res}; +} + +uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges) +{ + size_t size = 0; + for (const auto& range : unencryptedRanges) { + size += leb128_size(range.offset); + size += leb128_size(range.size); + } + return static_cast(size); +} + +uint8_t serialize_unencrypted_ranges(const ranges& unencryptedRanges, + uint8_t* buffer, + size_t bufferSize) +{ + auto writeAt = buffer; + auto end = buffer + bufferSize; + for (const auto& range : unencryptedRanges) { + auto rangeSize = leb128_size(range.offset) + leb128_size(range.size); + if (rangeSize > static_cast(end - writeAt)) { + break; + } + + writeAt += write_leb128(range.offset, writeAt); + writeAt += write_leb128(range.size, writeAt); + } + return writeAt - buffer; +} + +uint8_t deserialize_unencrypted_ranges(const uint8_t*& readAt, + const size_t bufferSize, + ranges& unencryptedRanges) +{ + auto start = readAt; + auto end = readAt + bufferSize; + while (readAt < end) { + size_t offset = read_leb128(readAt, end); + if (readAt == nullptr) { + break; + } + + size_t size = read_leb128(readAt, end); + if (readAt == nullptr) { + break; + } + unencryptedRanges.push_back({offset, size}); + } + + if (readAt != end) { + unencryptedRanges.clear(); + readAt = nullptr; + return 0; + } + + return readAt - start; +} + +bool validate_unencrypted_ranges(const ranges& unencryptedRanges, size_t frameSize) +{ + if (unencryptedRanges.empty()) { + return true; + } + + // validate that the ranges are in order and don't overlap + for (auto i = 0u; i < unencryptedRanges.size(); ++i) { + auto current = unencryptedRanges[i]; + // The current range should not overflow into the next range + // or if it is the last range, the end of the frame + auto maxEnd = + i + 1 < unencryptedRanges.size() ? unencryptedRanges[i + 1].offset : frameSize; + + auto [didOverflow, currentEnd] = OverflowAdd(current.offset, current.size); + if (didOverflow || currentEnd > maxEnd) { + return false; + } + } + + return true; +} + +size_t Reconstruct(ranges ranges, + const std::vector& rangeBytes, + const std::vector& otherBytes, + const array_view& output) +{ + size_t frameIndex = 0; + size_t rangeBytesIndex = 0; + size_t otherBytesIndex = 0; + + const auto CopyRangeBytes = [&](size_t size) { + std::memcpy(output.data() + frameIndex, rangeBytes.data() + rangeBytesIndex, size); + rangeBytesIndex += size; + frameIndex += size; + }; + + const auto CopyOtherBytes = [&](size_t size) { + std::memcpy(output.data() + frameIndex, otherBytes.data() + otherBytesIndex, size); + otherBytesIndex += size; + frameIndex += size; + }; + + for (const auto& range : ranges) { + if (range.offset > frameIndex) { + CopyOtherBytes(range.offset - frameIndex); + } + + CopyRangeBytes(range.size); + } + + if (otherBytesIndex < otherBytes.size()) { + CopyOtherBytes(otherBytes.size() - otherBytesIndex); + } + + return frameIndex; +} + +void inbound_frame_processor::clear() +{ + isEncrypted_ = false; + originalSize_ = 0; + truncatedNonce_ = std::numeric_limits::max(); + unencryptedRanges_.clear(); + authenticated_.clear(); + ciphertext_.clear(); + plaintext_.clear(); +} + +void inbound_frame_processor::parse_frame(array_view frame) +{ + clear(); + + constexpr auto MinSupplementalBytesSize = + AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); + if (frame.size() < MinSupplementalBytesSize) { + creator.log(dpp::ll_warning, "Encrypted frame is too small to contain min supplemental bytes"); + return; + } + + // Check the frame ends with the magic marker + auto magicMarkerBuffer = frame.end() - sizeof(magic_marker); + if (memcmp(magicMarkerBuffer, &MARKER_BYTES, sizeof(magic_marker)) != 0) { + return; + } + + // Read the supplemental bytes size + supplemental_bytes_size supplementalBytesSize; + auto supplementalBytesSizeBuffer = magicMarkerBuffer - sizeof(supplemental_bytes_size); + memcpy(&supplementalBytesSize, supplementalBytesSizeBuffer, sizeof(supplemental_bytes_size)); + + // Check the frame is large enough to contain the supplemental bytes + if (frame.size() < supplementalBytesSize) { + creator.log(dpp::ll_warning, "Encrypted frame is too small to contain supplemental bytes"); + return; + } + + // Check that supplemental bytes size is large enough to contain the supplemental bytes + if (supplementalBytesSize < MinSupplementalBytesSize) { + creator.log(dpp::ll_warning, "Supplemental bytes size is too small to contain supplemental bytes"); + return; + } + + auto supplementalBytesBuffer = frame.end() - supplementalBytesSize; + + // Read the tag + tag_ = make_array_view(supplementalBytesBuffer, AES_GCM_127_TRUNCATED_TAG_BYTES); + + // Read the nonce + auto nonceBuffer = supplementalBytesBuffer + AES_GCM_127_TRUNCATED_TAG_BYTES; + auto readAt = nonceBuffer; + auto end = supplementalBytesSizeBuffer; + truncatedNonce_ = read_leb128(readAt, end); + if (readAt == nullptr) { + creator.log(dpp::ll_warning, "Failed to read truncated nonce"); + return; + } + + // Read the unencrypted ranges + auto unencryptedRangesSize = end - readAt; + deserialize_unencrypted_ranges(readAt, unencryptedRangesSize, unencryptedRanges_); + if (readAt == nullptr) { + creator.log(dpp::ll_warning, "Failed to read unencrypted ranges"); + return; + } + + if (!validate_unencrypted_ranges(unencryptedRanges_, frame.size())) { + creator.log(dpp::ll_warning, "Invalid unencrypted ranges"); + return; + } + + // This is overly aggressive but will keep reallocations to a minimum + authenticated_.reserve(frame.size()); + ciphertext_.reserve(frame.size()); + plaintext_.reserve(frame.size()); + + originalSize_ = frame.size(); + + // Split the frame into authenticated and ciphertext bytes + size_t frameIndex = 0; + for (const auto& range : unencryptedRanges_) { + auto encryptedBytes = range.offset - frameIndex; + if (encryptedBytes > 0) { + add_ciphertext_bytes(frame.data() + frameIndex, encryptedBytes); + } + + add_authenticated_bytes(frame.data() + range.offset, range.size); + frameIndex = range.offset + range.size; + } + auto actualFrameSize = frame.size() - supplementalBytesSize; + if (frameIndex < actualFrameSize) { + add_ciphertext_bytes(frame.data() + frameIndex, actualFrameSize - frameIndex); + } + + // Make sure the plaintext buffer is the same size as the ciphertext buffer + plaintext_.resize(ciphertext_.size()); + + // We've successfully parsed the frame + // Mark the frame as encrypted + isEncrypted_ = true; +} + +size_t inbound_frame_processor::reconstruct_frame(array_view frame) const +{ + if (!isEncrypted_) { + creator.log(dpp::ll_warning, "Cannot reconstruct an invalid encrypted frame"); + return 0; + } + + if (authenticated_.size() + plaintext_.size() > frame.size()) { + creator.log(dpp::ll_warning, "Frame is too small to contain the decrypted frame"); + return 0; + } + + return Reconstruct(unencryptedRanges_, authenticated_, plaintext_, frame); +} + +void inbound_frame_processor::add_authenticated_bytes(const uint8_t* data, size_t size) +{ + authenticated_.resize(authenticated_.size() + size); + memcpy(authenticated_.data() + authenticated_.size() - size, data, size); +} + +void inbound_frame_processor::add_ciphertext_bytes(const uint8_t* data, size_t size) +{ + ciphertext_.resize(ciphertext_.size() + size); + memcpy(ciphertext_.data() + ciphertext_.size() - size, data, size); +} + +void outbound_frame_processor::reset() +{ + codec_ = codec::cd_unknown; + frameIndex_ = 0; + unencryptedBytes_.clear(); + encryptedBytes_.clear(); + unencryptedRanges_.clear(); +} + +void outbound_frame_processor::process_frame(array_view frame, codec codec) +{ + reset(); + + codec_ = codec; + unencryptedBytes_.reserve(frame.size()); + encryptedBytes_.reserve(frame.size()); + + bool success = false; + switch (codec) { + case codec::cd_opus: + success = codec_utils::process_frame_opus(*this, frame); + break; + case codec::cd_vp8: + success = codec_utils::process_frame_vp8(*this, frame); + break; + case codec::cd_vp9: + success = codec_utils::process_frame_vp9(*this, frame); + break; + case codec::cd_h264: + success = codec_utils::process_frame_h264(*this, frame); + break; + case codec::cd_h265: + success = codec_utils::process_frame_h265(*this, frame); + break; + case codec::cd_av1: + success = codec_utils::process_frame_av1(*this, frame); + break; + default: + throw dpp::logic_exception("Unsupported codec for frame encryption"); + } + + if (!success) { + frameIndex_ = 0; + unencryptedBytes_.clear(); + encryptedBytes_.clear(); + unencryptedRanges_.clear(); + add_encrypted_bytes(frame.data(), frame.size()); + } + + ciphertextBytes_.resize(encryptedBytes_.size()); +} + +size_t outbound_frame_processor::reconstruct_frame(array_view frame) +{ + if (unencryptedBytes_.size() + ciphertextBytes_.size() > frame.size()) { + creator.log(dpp::ll_warning, "Frame is too small to contain the encrypted frame"); + return 0; + } + + return Reconstruct(unencryptedRanges_, unencryptedBytes_, ciphertextBytes_, frame); +} + +void outbound_frame_processor::add_unencrypted_bytes(const uint8_t* bytes, size_t size) +{ + if (!unencryptedRanges_.empty() && + unencryptedRanges_.back().offset + unencryptedRanges_.back().size == frameIndex_) { + // extend the last range + unencryptedRanges_.back().size += size; + } + else { + // add a new range (offset, size) + unencryptedRanges_.push_back({frameIndex_, size}); + } + + unencryptedBytes_.resize(unencryptedBytes_.size() + size); + memcpy(unencryptedBytes_.data() + unencryptedBytes_.size() - size, bytes, size); + frameIndex_ += size; +} + +void outbound_frame_processor::add_encrypted_bytes(const uint8_t* bytes, size_t size) +{ + encryptedBytes_.resize(encryptedBytes_.size() + size); + memcpy(encryptedBytes_.data() + encryptedBytes_.size() - size, bytes, size); + frameIndex_ += size; +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/frame_processors.h b/src/dpp/dave/frame_processors.h new file mode 100755 index 0000000000..26e58d0b42 --- /dev/null +++ b/src/dpp/dave/frame_processors.h @@ -0,0 +1,298 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include "common.h" +#include "array_view.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief Range inside a frame + */ +struct range { + size_t offset; + size_t size; +}; + +/** + * @brief Vector of ranges in a frame + */ +using ranges = std::vector; + +/** + * @brief Get total size of unencrypted ranges + * @param unencryptedRanges unencrypted ranges + * @return size + */ +uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges); + +/** + * @brief Serialise unencrypted ranges + * @param unencryptedRanges unencrypted ranges + * @param buffer buffer to serialise to + * @param bufferSize size of buffer + * @return size of ranges written + */ +uint8_t serialize_unencrypted_ranges(const ranges& unencryptedRanges, uint8_t* buffer, size_t bufferSize); + +/** + * @brief Deserialise unencrypted ranges + * @param buffer buffer to write to + * @param bufferSize buffer size + * @param unencryptedRanges unencrypted ranges to write to + * @return size of unencrypted ranges written + */ +uint8_t deserialize_unencrypted_ranges(const uint8_t*& buffer, const size_t bufferSize, ranges& unencryptedRanges); + +/** + * @brief Validate unencrypted ranges + * @param unencryptedRanges unencrypted ranges + * @param frameSize frame size + * @return true if validated + */ +bool validate_unencrypted_ranges(const ranges& unencryptedRanges, size_t frameSize); + +/** + * @brief Processes inbound frames from the decryptor + */ +class inbound_frame_processor { +public: + /** + * @brief Create inbound frame processor + * @param _creator creating cluster + */ + inbound_frame_processor(dpp::cluster& _creator) : creator(_creator) { }; + + /** + * @brief Parse inbound frame + * @param frame frame bytes + */ + void parse_frame(array_view frame); + + /** + * @brief Rebuild frame after decryption + * @param frame frame bytes + * @return size of reconstructed frame + */ + [[nodiscard]] size_t reconstruct_frame(array_view frame) const; + + /** + * @brief True if encrypted + * @return is encrypted + */ + [[nodiscard]] bool is_encrypted() const { + return isEncrypted_; + } + + /** + * @brief Get size + * @return Original frame size + */ + [[nodiscard]] size_t size() const { + return originalSize_; + } + + /** + * @brief Clear the processor state + */ + void clear(); + + /** + * @brief get AEAD tag for frame processor + * @return AEAD tag + */ + [[nodiscard]] array_view get_tag() const { + return tag_; + } + + /** + * @brief Get truncated sync nonce + * @return truncated sync nonce + */ + [[nodiscard]] truncated_sync_nonce get_truncated_nonce() const { + return truncatedNonce_; + } + + /** + * @brief Get authenticated AEAD data + * @return AEAD auth data + */ + [[nodiscard]] array_view get_authenticated_data() const { + return make_array_view(authenticated_.data(), authenticated_.size()); + } + + /** + * @brief Get ciphertext + * @return Ciphertext view + */ + [[nodiscard]] array_view get_ciphertext() const { + return make_array_view(ciphertext_.data(), ciphertext_.size()); + } + + /** + * @brief Get plain text + * @return Plain text view + */ + [[nodiscard]] array_view get_plaintext() { return make_array_view(plaintext_); } + +private: + /** + * @brief Add authenticated bytes + * @param data authenticated data + * @param size authenticated data size + */ + void add_authenticated_bytes(const uint8_t* data, size_t size); + + /** + * @brief Add ciphertext bytes + * @param data ciphertext data + * @param size ciphertext data size + */ + void add_ciphertext_bytes(const uint8_t* data, size_t size); + + bool isEncrypted_{false}; + size_t originalSize_{0}; + array_view tag_; + truncated_sync_nonce truncatedNonce_; + ranges unencryptedRanges_; + std::vector authenticated_; + std::vector ciphertext_; + std::vector plaintext_; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +/** + * @brief Outbound frame processor, processes outbound frames for encryption + */ +class outbound_frame_processor { +public: + /** + * @brief Create outbound frame processor + * @param _creator creating cluster + */ + outbound_frame_processor(dpp::cluster& _creator) : creator(_creator) { }; + + /** + * @brief Process outbound frame + * @param frame frame data + * @param codec codec to use + */ + void process_frame(array_view frame, codec codec); + + /** + * @brief Reconstruct frame + * @param frame frame data + * @return size of reconstructed frame + */ + size_t reconstruct_frame(array_view frame); + + /** + * @brief Get codec + * @return codec + */ + [[nodiscard]] codec get_codec() const { + return codec_; + } + + /** + * @brief Get unencrypted bytes + * @return unencrypted bytes + */ + [[nodiscard]] const std::vector& get_unencrypted_bytes() const { + return unencryptedBytes_; + } + + /** + * @brief Get encrypted bytes + * @return Encrypted bytes + */ + [[nodiscard]] const std::vector& get_encrypted_bytes() const { + return encryptedBytes_; + } + + /** + * @brief Get ciphertext bytes + * @return ciphertext bytes + */ + [[nodiscard]] std::vector& get_ciphertext_bytes() { + return ciphertextBytes_; + } + + /** + * @brief Get unencrypted bytes + * @return unencrypted bytes + */ + [[nodiscard]] const ranges& get_unencrypted_ranges() const { + return unencryptedRanges_; + } + + /** + * @brief Reset outbound processor + */ + void reset(); + + /** + * @brief Add unencrypted bytes + * @param bytes unencrypted bytes + * @param size unencrypted size + */ + void add_unencrypted_bytes(const uint8_t* bytes, size_t size); + + /** + * @brief Add encrypted bytes + * @param bytes encrypted bytes + * @param size encrypted size + */ + void add_encrypted_bytes(const uint8_t* bytes, size_t size); + +private: + codec codec_{codec::cd_unknown}; + size_t frameIndex_{0}; + std::vector unencryptedBytes_; + std::vector encryptedBytes_; + std::vector ciphertextBytes_; + ranges unencryptedRanges_; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/key_ratchet.h b/src/dpp/dave/key_ratchet.h new file mode 100755 index 0000000000..3847f5f757 --- /dev/null +++ b/src/dpp/dave/key_ratchet.h @@ -0,0 +1,64 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include "common.h" + +namespace dpp::dave { + +/** + * @brief Key generation number + */ +using key_generation = uint32_t; + +/** + * @brief Represents the interface used for a key ratchet. + * A key ratchet is a way of propogating key pairs up the tree used by MLS + * so we dont have to store O(n^n) key combinations. + */ +class key_ratchet_interface { // NOLINT +public: + /** + * @brief Default destructor + */ + virtual ~key_ratchet_interface() noexcept = default; + + /** + * @brief Get key for ratchet + * @param generation current generation number + * @return encryption key + */ + virtual encryption_key get_key(key_generation generation) noexcept = 0; + + /** + * @brief Delete key for ratchet + * @param generation current generation number + */ + virtual void delete_key(key_generation generation) noexcept = 0; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/leb128.cpp b/src/dpp/dave/leb128.cpp new file mode 100755 index 0000000000..8bbe12543f --- /dev/null +++ b/src/dpp/dave/leb128.cpp @@ -0,0 +1,85 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * https://webrtc.googlesource.com/src/+/refs/heads/main/modules/rtp_rtcp/source/leb128.cc + * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + ************************************************************************************/ +#include "leb128.h" + +namespace dpp::dave { + +size_t leb128_size(uint64_t value) +{ + int size = 0; + while (value >= 0x80) { + ++size; + value >>= 7; + } + return size + 1; +} + +uint64_t read_leb128(const uint8_t*& readAt, const uint8_t* end) +{ + uint64_t value = 0; + int fillBits = 0; + while (readAt != end && fillBits < 64 - 7) { + uint8_t leb128Byte = *readAt; + value |= uint64_t{leb128Byte & 0x7Fu} << fillBits; + ++readAt; + fillBits += 7; + if ((leb128Byte & 0x80) == 0) { + return value; + } + } + // Read 9 bytes and didn't find the terminator byte. Check if 10th byte + // is that terminator, however to fit result into uint64_t it may carry only + // single bit. + if (readAt != end && *readAt <= 1) { + value |= uint64_t{*readAt} << fillBits; + ++readAt; + return value; + } + // Failed to find terminator leb128 byte. + readAt = nullptr; + return 0; +} + +size_t write_leb128(uint64_t value, uint8_t* buffer) +{ + int size = 0; + while (value >= 0x80) { + buffer[size] = 0x80 | (value & 0x7F); + ++size; + value >>= 7; + } + buffer[size] = value; + ++size; + return size; +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/leb128.h b/src/dpp/dave/leb128.h new file mode 100755 index 0000000000..292df06864 --- /dev/null +++ b/src/dpp/dave/leb128.h @@ -0,0 +1,69 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * https://webrtc.googlesource.com/src/+/refs/heads/main/modules/rtp_rtcp/source/leb128.cc + * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + ************************************************************************************/ +#pragma once + +#include +#include + +namespace dpp::dave { + +/** + * @brief Maximum size of LEB128 value + */ +constexpr size_t LEB128_MAX_SIZE = 10; + +/** + * @brief Returns number of bytes needed to store `value` in leb128 format. + * @param value value to return size for + * @return size of leb128 + */ +size_t leb128_size(uint64_t value); + +/** + * @brief Reads leb128 encoded value and advance read_at by number of bytes consumed. + * Sets read_at to nullptr on error. + * @param readAt start position + * @param end end position + * @return decoded value + */ +uint64_t read_leb128(const uint8_t*& readAt, const uint8_t* end); + +/** + * @brief Encodes `value` in leb128 format. Assumes buffer has size of + * at least Leb128Size(value). Returns number of bytes consumed. + * @param value value to encode + * @param buffer buffer to encode into + * @return size of encoding + */ +size_t write_leb128(uint64_t value, uint8_t* buffer); + +} // namespace dpp::dave + diff --git a/src/dpp/dave/mls_key_ratchet.cpp b/src/dpp/dave/mls_key_ratchet.cpp new file mode 100755 index 0000000000..1f8b1149dc --- /dev/null +++ b/src/dpp/dave/mls_key_ratchet.cpp @@ -0,0 +1,56 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "mls_key_ratchet.h" +#include + +namespace dpp::dave { + +mls_key_ratchet::mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes baseSecret) noexcept + : hashRatchet_(suite, std::move(baseSecret)), creator(cl) +{ +} + +mls_key_ratchet::~mls_key_ratchet() noexcept = default; + +encryption_key mls_key_ratchet::get_key(key_generation generation) noexcept +{ + creator.log(dpp::ll_debug, "Retrieving key for generation " + std::to_string(generation) + " from HashRatchet"); + try { + auto keyAndNonce = hashRatchet_.get(generation); + return std::move(keyAndNonce.key.as_vec()); + } + catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to retrieve key for generation " + std::to_string(generation) + ": " + std::string(e.what())); + return {}; + } +} + +void mls_key_ratchet::delete_key(key_generation generation) noexcept +{ + hashRatchet_.erase(generation); +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/mls_key_ratchet.h b/src/dpp/dave/mls_key_ratchet.h new file mode 100755 index 0000000000..0a4d053819 --- /dev/null +++ b/src/dpp/dave/mls_key_ratchet.h @@ -0,0 +1,79 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include "key_ratchet.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief An implementation of the key ratchet using MLS + */ +class mls_key_ratchet : public key_ratchet_interface { // NOLINT +public: + /** + * @brief Constructor + * @param suite MLS ciphersuite to use + * @param baseSecret base secret + */ + mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes baseSecret) noexcept; + + /** + * @brief Destructor + */ + ~mls_key_ratchet() noexcept override; + + /** + * @brief Gey key for ratchet + * @param generation current generation + * @return encryption key + */ + encryption_key get_key(key_generation generation) noexcept override; + + /** + * Delete key for ratchet + * @param generation current generation + */ + void delete_key(key_generation generation) noexcept override; + +private: + /** + * @brief MLS hash ratchet + */ + ::mlspp::HashRatchet hashRatchet_; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/openssl_aead_cipher.cpp b/src/dpp/dave/openssl_aead_cipher.cpp new file mode 100755 index 0000000000..fcb2cad352 --- /dev/null +++ b/src/dpp/dave/openssl_aead_cipher.cpp @@ -0,0 +1,160 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#include "openssl_aead_cipher.h" +#include +#include +#include +#include +#include +#include "common.h" + +namespace dpp::dave { + +openssl_aead_cipher::openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& encryptionKey) : + cipher_interface(_creator), + cipherCtx_(EVP_CIPHER_CTX_new()), + key_(std::vector(encryptionKey.data(), encryptionKey.data() + encryptionKey.size())) { +} + +openssl_aead_cipher::~openssl_aead_cipher() { + EVP_CIPHER_CTX_free(cipherCtx_); +} + +bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) { + + int len{}; + + if (EVP_EncryptInit_ex(cipherCtx_, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Set IV length + */ + if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* Initialise key and IV */ + if (EVP_EncryptInit_ex(cipherCtx_, nullptr, nullptr, key_.data(), nonceBuffer.data()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Provide any AAD data. This can be called zero or more times as + * required + */ + if (EVP_EncryptUpdate(cipherCtx_, nullptr, &len, additionalData.data(), (int)additionalData.size()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (EVP_EncryptUpdate(cipherCtx_, ciphertextBufferOut.data(), &len, plaintextBuffer.data(), (int)plaintextBuffer.size()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if (EVP_EncryptFinal_ex(cipherCtx_, ciphertextBufferOut.data() + len, &len) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* Get the tag */ + if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_GET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, tagBufferOut.data()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + return true; +} + +bool openssl_aead_cipher::decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) { + + int len = 0; + + /* Initialise the decryption operation. */ + if (EVP_DecryptInit_ex(cipherCtx_, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ + if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* Initialise key and IV */ + if (EVP_DecryptInit_ex(cipherCtx_, nullptr, nullptr, key_.data(), nonceBuffer.data()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Provide any AAD data. This can be called zero or more times as + * required + */ + if (EVP_DecryptUpdate(cipherCtx_, nullptr, &len, additionalData.data(), (int)additionalData.size()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if (EVP_DecryptUpdate(cipherCtx_, plaintextBufferOut.data(), &len, ciphertextBuffer.data(), (int)ciphertextBuffer.size()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, (void*)tagBuffer.data()) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + /* + * Finalise the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + if (EVP_DecryptFinal_ex(cipherCtx_, plaintextBufferOut.data() + len, &len) == 0) { + creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); + return false; + } + + return true; +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/openssl_aead_cipher.h b/src/dpp/dave/openssl_aead_cipher.h new file mode 100755 index 0000000000..b69ae2c322 --- /dev/null +++ b/src/dpp/dave/openssl_aead_cipher.h @@ -0,0 +1,99 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include "cipher_interface.h" + +namespace dpp { + class cluster; +} + +namespace dpp::dave { + +/** + * @brief OpenSSL AES 128 GCM AEAD cipher + * + * Replaces the boringSSL AES cipher in the Discord implementation, so we don't + * have a conflicting dependency. + */ +class openssl_aead_cipher : public cipher_interface { // NOLINT +public: + + /** + * @brief constructor + * @param _creator Creator + * @param encryptionKey encryption key + */ + openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& encryptionKey); + + /** + * @brief Destructor + */ + ~openssl_aead_cipher() override; + + /** + * @brief Returns true if valid + * @return True if valid + */ + [[nodiscard]] bool inline is_valid() const { + return cipherCtx_ != nullptr; + } + + /** + * @brief Encrypt plaintext to ciphertext and authenticate it with tag/AAD + * @param ciphertextBufferOut ciphertext + * @param plaintextBuffer plaintext + * @param nonceBuffer nonce/IV + * @param additionalData additional authenticated data + * @param tagBufferOut tag + * @return True if encryption succeeded + */ + bool encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) override; + + /** + * @brief Decrypt ciphertext to plaintext if it authenticates with tag/AAD + * @param plaintextBufferOut plaintext + * @param ciphertextBuffer ciphertext + * @param tagBuffer tag + * @param nonceBuffer nonce/IV + * @param additionalData additional authenticated data + * @return True if decryption succeeded + */ + bool decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) override; + +private: + /** + * @brief Using EVP_CIPHER_CTX instead of EVP_AEAD_CTX + */ + EVP_CIPHER_CTX* cipherCtx_; + + /** + * @brief Encryption/decryption key + */ + std::vector key_; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/parameters.cpp b/src/dpp/dave/parameters.cpp new file mode 100755 index 0000000000..965ba80b39 --- /dev/null +++ b/src/dpp/dave/parameters.cpp @@ -0,0 +1,79 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "parameters.h" + +namespace dpp::dave::mls { + +::mlspp::CipherSuite::ID ciphersuite_id_for_protocol_version(protocol_version version) noexcept +{ + return ::mlspp::CipherSuite::ID::P256_AES128GCM_SHA256_P256; +} + +::mlspp::CipherSuite ciphersuite_for_protocol_version(protocol_version version) noexcept +{ + return ::mlspp::CipherSuite{ciphersuite_id_for_protocol_version(version)}; +} + +::mlspp::CipherSuite::ID ciphersuite_id_for_signature_version(signature_version version) noexcept +{ + return ::mlspp::CipherSuite::ID::P256_AES128GCM_SHA256_P256; +} + +::mlspp::CipherSuite ciphersuite_for_signature_version(signature_version version) noexcept +{ + return ::mlspp::CipherSuite{ciphersuite_id_for_protocol_version(version)}; +} + +::mlspp::Capabilities leaf_node_capabilities_for_protocol_version(protocol_version version) noexcept +{ + auto capabilities = ::mlspp::Capabilities::create_default(); + + capabilities.cipher_suites = {ciphersuite_id_for_protocol_version(version)}; + capabilities.credentials = {::mlspp::CredentialType::basic}; + + return capabilities; +} + +::mlspp::ExtensionList leaf_node_extensions_for_protocol_version(protocol_version version) noexcept +{ + return ::mlspp::ExtensionList{}; +} + +::mlspp::ExtensionList group_extensions_for_protocol_version( + protocol_version version, + const ::mlspp::ExternalSender& externalSender) noexcept +{ + auto extensionList = ::mlspp::ExtensionList{}; + + extensionList.add(::mlspp::ExternalSendersExtension{{ + {externalSender.signature_key, externalSender.credential}, + }}); + + return extensionList; +} + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/parameters.h b/src/dpp/dave/parameters.h new file mode 100755 index 0000000000..a5a8d4a813 --- /dev/null +++ b/src/dpp/dave/parameters.h @@ -0,0 +1,85 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include + +#include "version.h" + +namespace dpp::dave::mls { + +/** + * @brief Get ciphersuite id for protocol version + * @param version protocol version + * @return ciphersuite id + */ +::mlspp::CipherSuite::ID ciphersuite_id_for_protocol_version(protocol_version version) noexcept; + +/** + * @brief Get ciphersuite for protocol version + * @param version protocol version + * @return ciphersuite + */ +::mlspp::CipherSuite ciphersuite_for_protocol_version(protocol_version version) noexcept; + +/** + * @brief Get ciphersuite id for signature version + * @param version signature version + * @return Ciphersuite id + */ +::mlspp::CipherSuite::ID ciphersuite_id_for_signature_version(signature_version version) noexcept; + +/** + * @brief Get ciphersuite for singnature version + * @param version signature version + * @return Ciphersuite + */ +::mlspp::CipherSuite ciphersuite_for_signature_version(signature_version version) noexcept; + +/** + * @brief Get leaf node capabilities for protocol version + * @param version protocol version + * @return capabilities + */ +::mlspp::Capabilities leaf_node_capabilities_for_protocol_version(protocol_version version) noexcept; + +/** + * @brief Get leaf node extensions for protocol version + * @param version protocol version + * @return extension list + */ +::mlspp::ExtensionList leaf_node_extensions_for_protocol_version(protocol_version version) noexcept; + +/** + * @brief Get group extensions for protocol version + * @param version protocol bersion + * @param externalSender external sender + * @return extension list + */ +::mlspp::ExtensionList group_extensions_for_protocol_version(protocol_version version, const ::mlspp::ExternalSender& externalSender) noexcept; + +} // namespace dpp::dave::mls diff --git a/src/dpp/dave/persisted_key_pair.cpp b/src/dpp/dave/persisted_key_pair.cpp new file mode 100755 index 0000000000..77ea4f415e --- /dev/null +++ b/src/dpp/dave/persisted_key_pair.cpp @@ -0,0 +1,103 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "persisted_key_pair.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "parameters.h" + +static const std::string SelfSignatureLabel = "DiscordSelfSignature"; + +static std::string MakeKeyID(const std::string& sessionID, ::mlspp::CipherSuite suite) +{ + return sessionID + "-" + std::to_string((uint16_t)suite.cipher_suite()) + "-" + std::to_string(dpp::dave::mls::KeyVersion); +} + +static std::mutex mtx; +static std::map> map; + +namespace dpp::dave::mls { + +static std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, ::mlspp::CipherSuite suite) +{ + std::lock_guard lk(mtx); + + std::string id = MakeKeyID(sessionID, suite); + + if (auto it = map.find(id); it != map.end()) { + return it->second; + } + + std::shared_ptr<::mlspp::SignaturePrivateKey> ret = ::dpp::dave::mls::detail::get_generic_persisted_key_pair(creator, ctx, id, suite); + + if (!ret) { + creator.log(dpp::ll_warning, "Failed to get key in get_persisted_key_pair"); + return nullptr; + } + + map.emplace(id, ret); + + return ret; +} + +std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, protocol_version version) +{ + return get_persisted_key_pair(creator, ctx, sessionID, ciphersuite_for_protocol_version(version)); +} + +KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version) +{ + auto suite = ciphersuite_for_signature_version(version); + auto pair = get_persisted_key_pair(creator, ctx, sessionID, suite); + + if (!pair) { + return {}; + } + + bytes sign_data = from_ascii(sessionID + ":") + pair->public_key.data; + + return { + pair->public_key.data.as_vec(), + std::move(pair->sign(suite, SelfSignatureLabel, sign_data).as_vec()), + }; +} + +bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version) +{ + std::string id = MakeKeyID(sessionID, ciphersuite_for_signature_version(version)); + std::lock_guard lk(mtx); + map.erase(id); + return ::dpp::dave::mls::detail::delete_generic_persisted_key_pair(creator, ctx, id); +} + +} // namespace dpp::dave::mls diff --git a/src/dpp/dave/persisted_key_pair.h b/src/dpp/dave/persisted_key_pair.h new file mode 100755 index 0000000000..7c13c6578b --- /dev/null +++ b/src/dpp/dave/persisted_key_pair.h @@ -0,0 +1,123 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "parameters.h" +#include "version.h" + +namespace dpp { + class cluster; +} + +namespace mlspp { + struct SignaturePrivateKey; +}; + +namespace dpp::dave::mls { + +/** + * @brief Key pair context type + */ +using key_pair_context_type = const char *; + +/** + * @brief Get persisted key pair + * @param ctx context (pass nullptr to generate transient key) + * @param sessionID session id (pass empty string to generate transient key) + * @param version Protocol version + * @return MLS signature private key + */ +std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, protocol_version version); + +/** + * @brief self signed signature and key + */ +struct KeyAndSelfSignature { + /** + * @brief key + */ + std::vector key; + /** + * @brief signature + */ + std::vector signature; +}; + +/** + * @brief Get persisted public key + * @param ctx context (set to nullptr to get transient key) + * @param sessionID session id (set to empty string to get transient key) + * @param version protocol version + * @return Key and self signature + */ +KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version); + +/** + * @brief Delete persisted key pair + * @param ctx context + * @param sessionID session ID + * @param version protocol version + * @return true if deleted + */ +bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version); + +/** + * @brief Key version for DAVE + */ +constexpr unsigned KeyVersion = 1; + +namespace detail { + /** + * Get generic persisted key pair + * @param ctx context + * @param id key ID + * @param suite ciphersuite + * @return signature and private key + */ + std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id, ::mlspp::CipherSuite suite); + + /** + * Delete generic persisted key pair + * @param ctx context + * @param id id + * @return true if deleted + */ + bool delete_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id); +} // namespace dpp::dave::mls::detail + +} // namespace dpp::dave::mls + + + diff --git a/src/dpp/dave/persisted_key_pair_generic.cpp b/src/dpp/dave/persisted_key_pair_generic.cpp new file mode 100755 index 0000000000..c0a473acc7 --- /dev/null +++ b/src/dpp/dave/persisted_key_pair_generic.cpp @@ -0,0 +1,188 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif +#include +#include +#include +#include +#include "parameters.h" +#include "persisted_key_pair.h" + +static const std::string_view KeyStorageDir = "Discord Key Storage"; + +static std::filesystem::path GetKeyStorageDirectory() +{ + std::filesystem::path dir; + +#if defined(__ANDROID__) + dir = std::filesystem::path("/data/data"); + + { + std::ifstream idFile("/proc/self/cmdline", std::ios_base::in); + std::string appId; + std::getline(idFile, appId, '\0'); + dir /= appId; + } +#else // __ANDROID__ +#if defined(_WIN32) + if (const wchar_t* appdata = _wgetenv(L"LOCALAPPDATA")) { + dir = std::filesystem::path(appdata); + } +#else // _WIN32 + if (const char* xdg = getenv("XDG_CONFIG_HOME")) { + dir = std::filesystem::path(xdg); + } + else if (const char* home = getenv("HOME")) { + dir = std::filesystem::path(home); + dir /= ".config"; + } +#endif // !_WIN32 + else { + return dir; + } +#endif // !__ANDROID__ + + return dir / KeyStorageDir; +} + +namespace dpp::dave::mls::detail { + +std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id, ::mlspp::CipherSuite suite) +{ + ::mlspp::SignaturePrivateKey ret; + std::string curstr; + std::filesystem::path dir = GetKeyStorageDirectory(); + + if (dir.empty()) { + creator.log(dpp::ll_warning, "Failed to determine key storage directory in get_persisted_key_pair"); + return nullptr; + } + + std::error_code errc; + std::filesystem::create_directories(dir, errc); + if (errc) { + creator.log(dpp::ll_warning, "Failed to create key storage directory in get_persisted_key_pair: " + std::to_string(errc.value())); + return nullptr; + } + + std::filesystem::path file = dir / (id + ".key"); + + if (std::filesystem::exists(file)) { + std::ifstream ifs(file, std::ios_base::in | std::ios_base::binary); + if (!ifs) { + creator.log(dpp::ll_warning, "Failed to open key in get_persisted_key_pair"); + return nullptr; + } + + std::stringstream s; + s << ifs.rdbuf(); + curstr = s.str(); + if (!ifs) { + creator.log(dpp::ll_warning, "Failed to read key in get_persisted_key_pair"); + return nullptr; + } + + try { + ret = ::mlspp::SignaturePrivateKey::from_jwk(suite, curstr); + } + catch (std::exception& ex) { + creator.log(dpp::ll_warning, "Failed to parse key in get_persisted_key_pair: " + std::string(ex.what())); + return nullptr; + } + } + else { + ret = ::mlspp::SignaturePrivateKey::generate(suite); + + std::string newstr = ret.to_jwk(suite); + + std::filesystem::path tmpfile = file; + tmpfile += ".tmp"; + +#ifdef _WIN32 + int fd = _wopen(tmpfile.c_str(), _O_WRONLY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); +#else + int fd = open(tmpfile.c_str(), + O_WRONLY | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); +#endif + if (fd < 0) { + creator.log(dpp::ll_warning, "Failed to open output file in get_persisted_key_pair: " + std::to_string(errno) + " (" + tmpfile.generic_string() + ")"); + return nullptr; + } + +#ifdef _WIN32 + int wret = _write(fd, newstr.c_str(), newstr.size()); + _close(fd); +#else + ssize_t wret = write(fd, newstr.c_str(), newstr.size()); + close(fd); +#endif + if (wret < 0 || (size_t)wret != newstr.size()) { + creator.log(dpp::ll_warning, "Failed to write output file in get_persisted_key_pair: " + std::to_string(errno)); + return nullptr; + } + + std::filesystem::rename(tmpfile, file, errc); + if (errc) { + creator.log(dpp::ll_warning, "Failed to rename output file in get_persisted_key_pair: " + std::to_string(errc.value())); + return nullptr; + } + } + + if (!ret.public_key.data.empty()) { + return std::make_shared<::mlspp::SignaturePrivateKey>(std::move(ret)); + } + return nullptr; + +} + +bool delete_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id) +{ + std::error_code errc; + std::filesystem::path dir = GetKeyStorageDirectory(); + if (dir.empty()) { + creator.log(dpp::ll_warning, "Failed to determine key storage directory in get_persisted_key_pair"); + return false; + } + + std::filesystem::path file = dir / (id + ".key"); + return std::filesystem::remove(file, errc); +} + +} // namespace dpp::dave::mls::detail + + + diff --git a/src/dpp/dave/scope_exit.h b/src/dpp/dave/scope_exit.h new file mode 100755 index 0000000000..219c51dc02 --- /dev/null +++ b/src/dpp/dave/scope_exit.h @@ -0,0 +1,103 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include + +namespace dpp::dave { + +/** + * @brief Calls a lambda when the class goes out of scope + */ +class [[nodiscard]] scope_exit final { +public: + /** + * Create new scope_exit with a lambda + * @tparam Cleanup lambda type + * @param cleanup lambda + */ + template explicit scope_exit(Cleanup&& cleanup) + : cleanup_{std::forward(cleanup)} + { + } + + /** + * @brief Move constructor + * @param rhs other object + */ + scope_exit(scope_exit&& rhs) : cleanup_{std::move(rhs.cleanup_)} + { + rhs.cleanup_ = nullptr; + } + + /** + * @brief Calls lambda + */ + ~scope_exit() + { + if (cleanup_) { + cleanup_(); + } + } + + /** + * @brief move assignment + * @param rhs other object + * @return self + */ + scope_exit& operator=(scope_exit&& rhs) + { + cleanup_ = std::move(rhs.cleanup_); + rhs.cleanup_ = nullptr; + return *this; + } + + /** + * @brief Clear the lambda so it isn't called + */ + void dismiss() { cleanup_ = nullptr; } + +private: + /** + * @brief Deleted copy constructor + */ + scope_exit(scope_exit const&) = delete; + + /** + * @brief Deleted assignment operator + * @return + */ + scope_exit& operator=(scope_exit const&) = delete; + + /** + * @brief Lambda to call + */ + std::function cleanup_; +}; + +} // namespace dpp::dave + diff --git a/src/dpp/dave/session.cpp b/src/dpp/dave/session.cpp new file mode 100755 index 0000000000..b619a2913a --- /dev/null +++ b/src/dpp/dave/session.cpp @@ -0,0 +1,759 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "session.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "mls_key_ratchet.h" +#include "user_credential.h" +#include "parameters.h" +#include "persisted_key_pair.h" +#include "util.h" + +#include "openssl/evp.h" + +#define TRACK_MLS_ERROR(reason) \ + if (onMLSFailureCallback_) { \ + onMLSFailureCallback_(__FUNCTION__, reason); \ + } + +namespace dpp::dave::mls { + +struct queued_proposal { + ::mlspp::ValidatedContent content; + ::mlspp::bytes_ns::bytes ref; +}; + +session::session(dpp::cluster& cluster, key_pair_context_type context, const std::string& authSessionId, mls_failure_callback callback) noexcept + : signingKeyId_(authSessionId), keyPairContext_(context), onMLSFailureCallback_(std::move(callback)), creator(cluster) +{ + creator.log(dpp::ll_debug, "Creating a new MLS session"); +} + +session::~session() noexcept = default; + +void session::init(protocol_version version, uint64_t groupId, std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept { + reset(); + + selfUserId_ = selfUserId; + + creator.log(dpp::ll_debug, "Initializing MLS session with protocol version " + std::to_string(version) + " and group ID " + std::to_string(groupId)); + protocolVersion_ = version; + groupId_ = std::move(big_endian_bytes_from(groupId).as_vec()); + + init_leaf_node(selfUserId, transientKey); + + create_pending_group(); +} + +void session::reset() noexcept { + creator.log(dpp::ll_debug, "Resetting MLS session"); + + clear_pending_state(); + + currentState_.reset(); + outboundCachedGroupState_.reset(); + + protocolVersion_ = 0; + groupId_.clear(); +} + +void session::set_protocol_version(protocol_version version) noexcept { + if (version != protocolVersion_) { + // when we need to retain backwards compatibility + // there may be some changes to the MLS objects required here + // until then we can just update the stored version + protocolVersion_ = version; + } +} + +std::vector session::get_last_epoch_authenticator() const noexcept { + if (!currentState_) { + creator.log(dpp::ll_debug, "Cannot get epoch authenticator without an established MLS group"); + return {}; + } + return std::move(currentState_->epoch_authenticator().as_vec()); +} + +void session::set_external_sender(const std::vector &externalSenderPackage) noexcept +try { + if (currentState_) { + creator.log(dpp::ll_warning, "Cannot set external sender after joining/creating an MLS group"); + return; + } + + creator.log(dpp::ll_debug, "Unmarshalling MLS external sender"); + + externalSender_ = std::make_unique<::mlspp::ExternalSender>( + ::mlspp::tls::get<::mlspp::ExternalSender>(externalSenderPackage)); + + if (!groupId_.empty()) { + create_pending_group(); + } +} +catch (const std::exception& e) { + creator.log(dpp::ll_error, "Failed to unmarshal external sender: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return; +} + +std::optional> session::process_proposals(std::vector proposals, std::set const& recognizedUserIDs) noexcept +try { + if (!pendingGroupState_ && !currentState_) { + creator.log(dpp::ll_debug, "Cannot process proposals without any pending or established MLS group state"); + return std::nullopt; + } + + if (!stateWithProposals_) { + stateWithProposals_ = std::make_unique<::mlspp::State>( + pendingGroupState_ ? *pendingGroupState_ : *currentState_); + } + + creator.log(dpp::ll_debug, "Processing MLS proposals message of " + std::to_string(proposals.size()) + " bytes"); + + ::mlspp::tls::istream inStream(proposals); + + bool isRevoke = false; + inStream >> isRevoke; + + if (isRevoke) { + creator.log(dpp::ll_trace, "Revoking from proposals"); + } + + const auto suite = stateWithProposals_->cipher_suite(); + + if (isRevoke) { + std::vector<::mlspp::bytes_ns::bytes> refs; + inStream >> refs; + + for (const auto& ref : refs) { + bool found = false; + for (auto it = proposalQueue_.begin(); it != proposalQueue_.end(); it++) { + if (it->ref == ref) { + found = true; + proposalQueue_.erase(it); + break; + } + } + + if (!found) { + creator.log(dpp::ll_debug, "Cannot revoke unrecognized proposal ref"); + TRACK_MLS_ERROR("Unrecognized proposal revocation"); + return std::nullopt; + } + } + + stateWithProposals_ = std::make_unique<::mlspp::State>( + pendingGroupState_ ? *pendingGroupState_ : *currentState_); + + for (auto& prop : proposalQueue_) { + // success will queue the proposal, failure will throw + stateWithProposals_->handle(prop.content); + } + } + else { + std::vector<::mlspp::MLSMessage> messages; + inStream >> messages; + + for (const auto& proposalMessage : messages) { + auto validatedMessage = stateWithProposals_->unwrap(proposalMessage); + + if (!validate_proposal_message(validatedMessage.authenticated_content(), + *stateWithProposals_, + recognizedUserIDs)) { + return std::nullopt; + } + + // success will queue the proposal, failure will throw + stateWithProposals_->handle(validatedMessage); + + auto ref = suite.ref(validatedMessage.authenticated_content()); + + proposalQueue_.push_back({ + std::move(validatedMessage), + std::move(ref), + }); + } + } + + // generate a commit + auto commitSecret = ::mlspp::hpke::random_bytes(suite.secret_size()); + + auto commitOpts = ::mlspp::CommitOpts{ + {}, // no extra proposals + true, // inline tree in welcome + false, // do not force path + {} // default leaf node options + }; + + auto [commitMessage, welcomeMessage, newState] = + stateWithProposals_->commit(commitSecret, commitOpts, {}); + + creator.log(dpp::ll_debug, "Prepared commit/welcome/next state for MLS group from received proposals"); + + // combine the commit and welcome messages into a single buffer + auto outStream = ::mlspp::tls::ostream(); + outStream << commitMessage; + + // keep a copy of the commit, we can check incoming pending group commit later for a match + pendingGroupCommit_ = std::make_unique<::mlspp::MLSMessage>(std::move(commitMessage)); + + // if there were any add proposals in this commit, then we also include the welcome message + if (welcomeMessage.secrets.size() > 0) { + outStream << welcomeMessage; + } + + // cache the outbound state in case we're the winning sender + outboundCachedGroupState_ = std::make_unique<::mlspp::State>(std::move(newState)); + + + return outStream.bytes(); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to parse MLS proposals: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return std::nullopt; +} + +bool session::is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognizedUserIDs) const +{ + std::string uid = user_credential_to_string(cred, protocolVersion_); + if (uid.empty()) { + creator.log(dpp::ll_warning, "Attempted to verify credential of unexpected type"); + return false; + } + + if (recognizedUserIDs.find(uid) == recognizedUserIDs.end()) { + creator.log(dpp::ll_warning, "Attempted to verify credential for unrecognized user ID: " + uid); + return false; + } + + return true; +} + +bool session::validate_proposal_message(::mlspp::AuthenticatedContent const& message, ::mlspp::State const& targetState, std::set const& recognizedUserIDs) const { + if (message.wire_format != ::mlspp::WireFormat::mls_public_message) { + creator.log(dpp::ll_warning, "MLS proposal message must be PublicMessage"); + TRACK_MLS_ERROR("Invalid proposal wire format"); + return false; + } + + if (message.content.epoch != targetState.epoch()) { + creator.log(dpp::ll_warning, "MLS proposal message must be for current epoch (" + std::to_string(message.content.epoch) + " != " + std::to_string(targetState.epoch()) + ")"); + TRACK_MLS_ERROR("Proposal epoch mismatch"); + return false; + } + + if (message.content.content_type() != ::mlspp::ContentType::proposal) { + creator.log(dpp::ll_warning, "process_proposals called with non-proposal message"); + TRACK_MLS_ERROR("Unexpected message type"); + return false; + } + + if (message.content.sender.sender_type() != ::mlspp::SenderType::external) { + creator.log(dpp::ll_warning, "MLS proposal must be from external sender"); + TRACK_MLS_ERROR("Unexpected proposal sender type"); + return false; + } + + const auto& proposal = ::mlspp::tls::var::get<::mlspp::Proposal>(message.content.content); + switch (proposal.proposal_type()) { + case ::mlspp::ProposalType::add: { + const auto& credential = + ::mlspp::tls::var::get<::mlspp::Add>(proposal.content).key_package.leaf_node.credential; + if (!is_recognized_user_id(credential, recognizedUserIDs)) { + creator.log(dpp::ll_warning, "MLS proposal must be for recognised user"); + TRACK_MLS_ERROR("Unexpected user ID in add proposal"); + return false; + } + break; + } + case ::mlspp::ProposalType::remove: + // Remove proposals are always allowed (mlspp will validate that it's a recognized user) + break; + default: + creator.log(dpp::ll_warning, "MLS proposal must be add or remove"); + TRACK_MLS_ERROR("Unexpected proposal type"); + return false; + } + + return true; +} + +bool session::can_process_commit(const ::mlspp::MLSMessage& commit) noexcept +{ + if (!stateWithProposals_) { + return false; + } + + if (commit.group_id() != groupId_) { + creator.log(dpp::ll_warning, "MLS commit message was for unexpected group"); + return false; + } + + return true; +} + +roster_variant session::process_commit(std::vector commit) noexcept +try { + creator.log(dpp::ll_debug, "Processing commit"); + + auto commitMessage = ::mlspp::tls::get<::mlspp::MLSMessage>(commit); + + if (!can_process_commit(commitMessage)) { + creator.log(dpp::ll_warning, "process_commit called with unprocessable MLS commit"); + return ignored_t{}; + } + + // in case we're the sender of this commit + // we need to pull the cached state from our outbound cache + std::optional<::mlspp::State> optionalCachedState = std::nullopt; + if (outboundCachedGroupState_) { + optionalCachedState = *(outboundCachedGroupState_.get()); + } + + auto newState = stateWithProposals_->handle(commitMessage, optionalCachedState); + + if (!newState) { + creator.log(dpp::ll_warning, "MLS commit handling did not produce a new state"); + return failed_t{}; + } + + creator.log(dpp::ll_debug, "Successfully processed MLS commit, updating state; our leaf index is " + std::to_string(newState->index().val) + "; current epoch is " + std::to_string(newState->epoch())); + + roster_map ret = replace_state(std::make_unique<::mlspp::State>(std::move(*newState))); + + // reset the outbound cached group since we handled the commit for this epoch + outboundCachedGroupState_.reset(); + + clear_pending_state(); + + return ret; +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to process MLS commit: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return failed_t{}; +} + +std::optional session::process_welcome( + std::vector welcome, + std::set const& recognizedUserIDs) noexcept +try { + if (!has_cryptographic_state_for_welcome()) { + creator.log(dpp::ll_warning, "Missing local crypto state necessary to process MLS welcome"); + return std::nullopt; + } + + if (!externalSender_) { + creator.log(dpp::ll_warning, "Cannot process MLS welcome without an external sender"); + return std::nullopt; + } + + if (currentState_) { + creator.log(dpp::ll_warning, "Cannot process MLS welcome after joining/creating an MLS group"); + return std::nullopt; + } + + // unmarshal the incoming welcome + auto unmarshalledWelcome = ::mlspp::tls::get<::mlspp::Welcome>(welcome); + + // construct the state from the unmarshalled welcome + auto newState = std::make_unique<::mlspp::State>( + *joinInitPrivateKey_, + *selfHPKEPrivateKey_, + *selfSigPrivateKey_, + *joinKeyPackage_, + unmarshalledWelcome, + std::nullopt, + std::map<::mlspp::bytes_ns::bytes, ::mlspp::bytes_ns::bytes>()); + + // perform application-level verification of the new state + if (!verify_welcome_state(*newState, recognizedUserIDs)) { + creator.log(dpp::ll_warning, "Group received in MLS welcome is not valid"); + return std::nullopt; + } + + creator.log(dpp::ll_debug, "Successfully welcomed to MLS Group, our leaf index is " + std::to_string(newState->index().val) + "; current epoch is " + std::to_string(newState->epoch())); + + // make the verified state our new (and only) state + roster_map ret = replace_state(std::move(newState)); + + // clear out any pending state for creating/joining a group + clear_pending_state(); + + return ret; +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to create group state from MLS welcome: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return std::nullopt; +} + +roster_map session::replace_state(std::unique_ptr<::mlspp::State>&& state) +{ + roster_map newRoster; + for (const ::mlspp::LeafNode& node : state->roster()) { + if (node.credential.type() != ::mlspp::CredentialType::basic) { + continue; + } + + const auto& cred = node.credential.template get<::mlspp::BasicCredential>(); + + newRoster[from_big_endian_bytes(cred.identity)] = node.signature_key.data.as_vec(); + } + + roster_map changeMap; + + std::set_difference(newRoster.begin(), + newRoster.end(), + roster_.begin(), + roster_.end(), + std::inserter(changeMap, changeMap.end())); + + struct MissingItemWrapper { + roster_map& changeMap_; + + using iterator = roster_map::iterator; + using const_iterator = roster_map::const_iterator; + using value_type = roster_map::value_type; + + iterator insert(const_iterator it, const value_type& value) + { + return changeMap_.try_emplace(it, value.first, std::vector{}); + } + + iterator begin() { return changeMap_.begin(); } + + iterator end() { return changeMap_.end(); } + }; + + MissingItemWrapper wrapper{changeMap}; + + std::set_difference(roster_.begin(), + roster_.end(), + newRoster.begin(), + newRoster.end(), + std::inserter(wrapper, wrapper.end())); + + roster_ = std::move(newRoster); + currentState_ = std::move(state); + + return changeMap; +} + +bool session::has_cryptographic_state_for_welcome() const noexcept +{ + return joinKeyPackage_ && joinInitPrivateKey_ && selfSigPrivateKey_ && selfHPKEPrivateKey_; +} + +bool session::verify_welcome_state(::mlspp::State const& state, + std::set const& recognizedUserIDs) const +{ + if (!externalSender_) { + creator.log(dpp::ll_warning, "Cannot verify MLS welcome without an external sender"); + TRACK_MLS_ERROR("Missing external sender when processing Welcome"); + return false; + } + + auto ext = state.extensions().template find(); + if (!ext) { + creator.log(dpp::ll_warning, "MLS welcome missing external senders extension"); + TRACK_MLS_ERROR("Welcome message missing external sender extension"); + return false; + } + + if (ext->senders.size() != 1) { + creator.log(dpp::ll_warning, "MLS welcome lists unexpected number of external senders: " + std::to_string(ext->senders.size())); + TRACK_MLS_ERROR("Welcome message lists unexpected external sender count"); + return false; + } + + if (ext->senders.front() != *externalSender_) { + creator.log(dpp::ll_warning, "MLS welcome lists unexpected external sender"); + TRACK_MLS_ERROR("Welcome message lists unexpected external sender"); + return false; + } + + // TODO: Until we leverage revocation in the protocol + // if we re-enable this change we will refuse welcome messages + // because someone was previously supposed to be added but disconnected + // before all in-flight proposals were handled. + + for (const auto& leaf : state.roster()) { + if (!is_recognized_user_id(leaf.credential, recognizedUserIDs)) { + creator.log(dpp::ll_warning, "MLS welcome lists unrecognized user ID"); + } + } + + return true; +} + +void session::init_leaf_node(std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept +try { + auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); + + if (!transientKey) { + if (!signingKeyId_.empty()) { + transientKey = get_persisted_key_pair(creator, keyPairContext_, signingKeyId_, protocolVersion_); + if (!transientKey) { + creator.log(dpp::ll_warning, "Did not receive MLS signature private key from get_persisted_key_pair; aborting"); + return; + } + } + else { + transientKey = std::make_shared<::mlspp::SignaturePrivateKey>( + ::mlspp::SignaturePrivateKey::generate(ciphersuite)); + } + } + + selfSigPrivateKey_ = transientKey; + + auto selfCredential = create_user_credential(selfUserId, protocolVersion_); + + selfHPKEPrivateKey_ = std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); + + selfLeafNode_ = std::make_unique<::mlspp::LeafNode>(ciphersuite, selfHPKEPrivateKey_->public_key, selfSigPrivateKey_->public_key, std::move(selfCredential), + leaf_node_capabilities_for_protocol_version(protocolVersion_), ::mlspp::Lifetime::create_default(), + leaf_node_extensions_for_protocol_version(protocolVersion_), *selfSigPrivateKey_); + + creator.log(dpp::ll_debug, "Created MLS leaf node"); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to initialize MLS leaf node: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); +} + +void session::reset_join_key_package() noexcept +try { + if (!selfLeafNode_) { + creator.log(dpp::ll_warning, "Cannot initialize join key package without a leaf node"); + return; + } + + auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); + + joinInitPrivateKey_ = + std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); + + joinKeyPackage_ = + std::make_unique<::mlspp::KeyPackage>(ciphersuite, + joinInitPrivateKey_->public_key, + *selfLeafNode_, + leaf_node_extensions_for_protocol_version(protocolVersion_), + *selfSigPrivateKey_); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to initialize join key package: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); +} + +void session::create_pending_group() noexcept +try { + if (groupId_.empty()) { + creator.log(dpp::ll_warning, "Cannot create MLS group without a group ID"); + return; + } + + if (!externalSender_) { + creator.log(dpp::ll_warning, "Cannot create MLS group without ExternalSender"); + return; + } + + if (!selfLeafNode_) { + creator.log(dpp::ll_warning, "Cannot create MLS group without self leaf node"); + return; + } + + creator.log(dpp::ll_debug, "Creating a pending MLS group"); + + auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); + + pendingGroupState_ = std::make_unique<::mlspp::State>( + groupId_, + ciphersuite, + *selfHPKEPrivateKey_, + *selfSigPrivateKey_, + *selfLeafNode_, + group_extensions_for_protocol_version(protocolVersion_, *externalSender_)); + + creator.log(dpp::ll_debug, "Created a pending MLS group"); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to create MLS group: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return; +} + +std::vector session::get_marshalled_key_package() noexcept +try { + // key packages are not meant to be re-used + // so every time the client asks for a key package we create a new one + reset_join_key_package(); + + if (!joinKeyPackage_) { + creator.log(dpp::ll_warning, "Cannot marshal an uninitialized key package"); + return {}; + } + + return ::mlspp::tls::marshal(*joinKeyPackage_); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to marshal join key package: " + std::string(e.what())); + TRACK_MLS_ERROR(e.what()); + return {}; +} + +std::unique_ptr session::get_key_ratchet(std::string const& userId) const noexcept +{ + if (!currentState_) { + creator.log(dpp::ll_warning, "Cannot get key ratchet without an established MLS group"); + return nullptr; + } + + // change the string user ID to a little endian 64 bit user ID + auto u64userId = strtoull(userId.c_str(), nullptr, 10); + auto userIdBytes = ::mlspp::bytes_ns::bytes(sizeof(u64userId)); + memcpy(userIdBytes.data(), &u64userId, sizeof(u64userId)); + + // generate the base secret for the hash ratchet + auto baseSecret = + currentState_->do_export(session::USER_MEDIA_KEY_BASE_LABEL, userIdBytes, AES_GCM_128_KEY_BYTES); + + // this assumes the MLS ciphersuite produces a kAesGcm128KeyBytes sized key + // would need to be updated to a different ciphersuite if there's a future mismatch + return std::make_unique(creator, currentState_->cipher_suite(), std::move(baseSecret)); +} + +void session::get_pairwise_fingerprint(uint16_t version, + std::string const& userId, + pairwise_fingerprint_callback callback) const noexcept +try { + if (!currentState_ || !selfSigPrivateKey_) { + throw std::invalid_argument("No established MLS group"); + } + + uint64_t u64RemoteUserId = strtoull(userId.c_str(), nullptr, 10); + uint64_t u64SelfUserId = strtoull(selfUserId_.c_str(), nullptr, 10); + + auto it = roster_.find(u64RemoteUserId); + if (it == roster_.end()) { + throw std::invalid_argument("Unknown user ID: " + userId); + } + + ::mlspp::tls::ostream toHash1; + ::mlspp::tls::ostream toHash2; + + toHash1 << version; + toHash1.write_raw(it->second); + toHash1 << u64RemoteUserId; + + toHash2 << version; + toHash2.write_raw(selfSigPrivateKey_->public_key.data); + toHash2 << u64SelfUserId; + + std::vector> keyData = { + toHash1.bytes(), + toHash2.bytes(), + }; + + std::sort(keyData.begin(), keyData.end()); + + std::thread([callback = std::move(callback), + data = ::mlspp::bytes_ns::bytes(std::move(keyData[0])) + keyData[1]] { + static constexpr uint8_t salt[] = { + 0x24, + 0xca, + 0xb1, + 0x7a, + 0x7a, + 0xf8, + 0xec, + 0x2b, + 0x82, + 0xb4, + 0x12, + 0xb9, + 0x2d, + 0xab, + 0x19, + 0x2e, + }; + + constexpr uint64_t N = 16384, r = 8, p = 2, max_mem = 32 * 1024 * 1024; + constexpr size_t hash_len = 64; + + std::vector out(hash_len); + + int ret = EVP_PBE_scrypt((const char*)data.data(), + data.size(), + salt, + sizeof(salt), + N, + r, + p, + max_mem, + out.data(), + out.size()); + + if (ret == 1) { + callback(out); + } + else { + callback({}); + } + }).detach(); +} +catch (const std::exception& e) { + creator.log(dpp::ll_warning, "Failed to generate pairwise fingerprint: " + std::string(e.what())); + callback({}); +} + +void session::clear_pending_state() +{ + pendingGroupState_.reset(); + pendingGroupCommit_.reset(); + + joinInitPrivateKey_.reset(); + joinKeyPackage_.reset(); + + selfHPKEPrivateKey_.reset(); + + selfLeafNode_.reset(); + + stateWithProposals_.reset(); + proposalQueue_.clear(); +} + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/session.h b/src/dpp/dave/session.h new file mode 100755 index 0000000000..da488bb895 --- /dev/null +++ b/src/dpp/dave/session.h @@ -0,0 +1,286 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "persisted_key_pair.h" +#include "key_ratchet.h" +#include "version.h" + +namespace mlspp { + struct AuthenticatedContent; + struct Credential; + struct ExternalSender; + struct HPKEPrivateKey; + struct KeyPackage; + struct LeafNode; + struct MLSMessage; + struct SignaturePrivateKey; + class State; +} // namespace mlspp + +namespace dpp { + class cluster; +} + +namespace dpp::dave::mls { + +struct queued_proposal; + +/** + * @brief Represents an MLS DAVE session + */ +class session { // NOLINT +public: + /** + * @brief An MLS failure callback + */ + using mls_failure_callback = std::function; + + /** + * @brief Constructor + * @param context key pair context (set to nullptr to use a transient key pair) + * @param authSessionId auth session id (set to empty string to use a transient key pair) + * @param callback callback for failure + */ + session(dpp::cluster& cluster, key_pair_context_type context, const std::string& authSessionId, mls_failure_callback callback) noexcept; + + /** + * @brief Destructor + */ + ~session() noexcept; + + /** + * @brief Initalise session + * @note This is not done in the constructor, as we may need to do this again on upgrade or downgrade, + * whilst preserving other state set by the constructor. + * + * @param version protocol version + * @param groupId group id (channel id) + * @param selfUserId bot's user id + * @param transientKey transient private key + */ + void init(protocol_version version, uint64_t groupId, std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept; + + /** + * @brief Reset the session to defaults + */ + void reset() noexcept; + + /** + * @brief Set protocol version for session + * @param version protocol version + */ + void set_protocol_version(protocol_version version) noexcept; + + /** + * @brief Get protocol version for session + * @return protocol version + */ + [[nodiscard]] protocol_version get_protocol_version() const noexcept { + return protocolVersion_; + } + + /** + * @brief Get last epoch authenticator, the discord privacy code for the vc + * @return privacy code + */ + [[nodiscard]] std::vector get_last_epoch_authenticator() const noexcept; + + /** + * @brief Set external sender from external sender opcode + * @param externalSenderPackage external sender package + */ + void set_external_sender(std::vector const& externalSenderPackage) noexcept; + + /** + * @brief Process proposals from proposals opcode + * @param proposals proposals blob from websocket + * @param recognizedUserIDs list of recognised user IDs + * @return optional vector to send in reply as commit welcome + */ + std::optional> process_proposals(std::vector proposals, std::set const& recognizedUserIDs) noexcept; + + /** + * @brief Process commit message from discord websocket + * @param commit commit message from discord websocket + * @return roster list of people in the vc + */ + roster_variant process_commit(std::vector commit) noexcept; + + /** + * @brief Process welcome blob + * @param welcome welcome blob from discord + * @param recognizedUserIDs Recognised user ID list + * @return roster list of people in the vc + */ + std::optional process_welcome(std::vector welcome, std::set const& recognizedUserIDs) noexcept; + + /** + * @brief Get the bot user's key package for sending to websocket + * @return marshalled key package + */ + std::vector get_marshalled_key_package() noexcept; + + /** + * @brief Get key ratchet for a user (including the bot) + * @param userId User id to get ratchet for + * @return The user's key ratchet for use in an encryptor or decryptor + */ + [[nodiscard]] std::unique_ptr get_key_ratchet(std::string const& userId) const noexcept; + + /** + * @brief callback for completion of pairwise fingerprint + */ + using pairwise_fingerprint_callback = std::function const&)>; + + /** + * @brief Get pairwise fingerprint (used to validate discord member in vc) + * @warning This uses SCRYPT and is extremely resource intensive. It will spawn a thread + * which will call your callback on completion. + * @param version Should always be 0x00 + * @param userId User ID to get fingerprint for + * @param callback Callback for completion + */ + void get_pairwise_fingerprint(uint16_t version, std::string const& userId, pairwise_fingerprint_callback callback) const noexcept; + +private: + /** + * @brief Initialise leaf node + * @param selfUserId Bot user id + * @param transientKey Transient key + */ + void init_leaf_node(std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept; + + /** + * @brief Reset join key + */ + void reset_join_key_package() noexcept; + + /** + * @brief Create pending MLS group + */ + void create_pending_group() noexcept; + + /** + * @brief Is ready for welcome + * @return true if ready for welcome + */ + [[nodiscard]] bool has_cryptographic_state_for_welcome() const noexcept; + + /** + * @brief Check if user ID is valid + * @param cred MLS credential + * @param recognizedUserIDs list of recognised user IDs + * @return + */ + [[nodiscard]] bool is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognizedUserIDs) const; + + /** + * @brief Validate proposals message + * @param message authenticated content message + * @param targetState new state + * @param recognizedUserIDs recognised list of user IDs + * @return true if validated + */ + [[nodiscard]] bool validate_proposal_message(::mlspp::AuthenticatedContent const& message, ::mlspp::State const& targetState, std::set const& recognizedUserIDs) const; + + /** + * @brief Verify that welcome state is valid + * @param state current state + * @param recognizedUserIDs list of recognised user IDs + * @return + */ + [[nodiscard]] bool verify_welcome_state(::mlspp::State const& state, std::set const& recognizedUserIDs) const; + + /** + * @brief Check if can process a commit now + * @param commit Commit message + * @return true if can process + */ + [[nodiscard]] bool can_process_commit(const ::mlspp::MLSMessage& commit) noexcept; + + /** + * @brief Replace state with a new one + * @param state new state + * @return new roster list of users in VC + */ + roster_map replace_state(std::unique_ptr<::mlspp::State>&& state); + + /** + * @brief Clear pending MLS state + */ + void clear_pending_state(); + + /** + * @brief Constant media key label + */ + inline static const std::string USER_MEDIA_KEY_BASE_LABEL = "Discord Secure Frames v0"; + + protocol_version protocolVersion_; + std::vector groupId_; + std::string signingKeyId_; + std::string selfUserId_; + key_pair_context_type keyPairContext_{nullptr}; + + std::unique_ptr<::mlspp::LeafNode> selfLeafNode_; + std::shared_ptr<::mlspp::SignaturePrivateKey> selfSigPrivateKey_; + std::unique_ptr<::mlspp::HPKEPrivateKey> selfHPKEPrivateKey_; + + std::unique_ptr<::mlspp::HPKEPrivateKey> joinInitPrivateKey_; + std::unique_ptr<::mlspp::KeyPackage> joinKeyPackage_; + + std::unique_ptr<::mlspp::ExternalSender> externalSender_; + + std::unique_ptr<::mlspp::State> pendingGroupState_; + std::unique_ptr<::mlspp::MLSMessage> pendingGroupCommit_; + + std::unique_ptr<::mlspp::State> outboundCachedGroupState_; + + std::unique_ptr<::mlspp::State> currentState_; + roster_map roster_; + + std::unique_ptr<::mlspp::State> stateWithProposals_; + std::list proposalQueue_; + + mls_failure_callback onMLSFailureCallback_{}; + + /** + * @brief DPP Cluster, used for logging + */ + dpp::cluster& creator; +}; + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/user_credential.cpp b/src/dpp/dave/user_credential.cpp new file mode 100755 index 0000000000..f5fd9a6493 --- /dev/null +++ b/src/dpp/dave/user_credential.cpp @@ -0,0 +1,53 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "user_credential.h" +#include +#include "util.h" + +namespace dpp::dave::mls { + +::mlspp::Credential create_user_credential(const std::string& userId, protocol_version version) { + // convert the string user ID to a big endian uint64_t + auto userID = std::stoull(userId); + auto credentialBytes = big_endian_bytes_from(userID); + + return ::mlspp::Credential::basic(credentialBytes); +} + +std::string user_credential_to_string(const ::mlspp::Credential& cred, protocol_version version) { + if (cred.type() != ::mlspp::CredentialType::basic) { + return ""; + } + + const auto& basic = cred.template get<::mlspp::BasicCredential>(); + + auto uidVal = from_big_endian_bytes(basic.identity); + + return std::to_string(uidVal); +} + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/user_credential.h b/src/dpp/dave/user_credential.h new file mode 100755 index 0000000000..1afa2b7c3b --- /dev/null +++ b/src/dpp/dave/user_credential.h @@ -0,0 +1,51 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include +#include "version.h" + +namespace dpp::dave::mls { + +/** + * @brief Create user credentials + * @param userId user id + * @param version protocol version + * @return + */ +::mlspp::Credential create_user_credential(const std::string& userId, protocol_version version); + +/** + * @brief Convert user credentials to string + * @param cred user credentials + * @param version protocol version + * @return user credentials as string + */ +std::string user_credential_to_string(const ::mlspp::Credential& cred, protocol_version version); + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/util.cpp b/src/dpp/dave/util.cpp new file mode 100755 index 0000000000..1abdcc2faf --- /dev/null +++ b/src/dpp/dave/util.cpp @@ -0,0 +1,54 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "util.h" + +namespace dpp::dave::mls { + +::mlspp::bytes_ns::bytes big_endian_bytes_from(uint64_t value) noexcept { + auto buffer = ::mlspp::bytes_ns::bytes(); + buffer.reserve(sizeof(value)); + + for (int i = sizeof(value) - 1; i >= 0; --i) { + buffer.push_back(static_cast(value >> (i * 8))); + } + + return buffer; +} + +uint64_t from_big_endian_bytes(const ::mlspp::bytes_ns::bytes& buffer) noexcept { + uint64_t val = 0; + + if (buffer.size() <= sizeof(val)) { + for (uint8_t byte : buffer) { + val = (val << 8) | byte; + } + } + + return val; +} + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/util.h b/src/dpp/dave/util.h new file mode 100755 index 0000000000..f351f45feb --- /dev/null +++ b/src/dpp/dave/util.h @@ -0,0 +1,48 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include +#include + +namespace dpp::dave::mls { + +/** + * @brief Convert uint64_t to bytes + * @param value 64 bit value + * @return bytes + */ +::mlspp::bytes_ns::bytes big_endian_bytes_from(uint64_t value) noexcept; + +/** + * @brief Convert uint64_t to bytes + * @param value bytes + * @return 64 bit value + */ +uint64_t from_big_endian_bytes(const ::mlspp::bytes_ns::bytes& value) noexcept; + +} // namespace dpp::dave::mls + + diff --git a/src/dpp/dave/version.cpp b/src/dpp/dave/version.cpp new file mode 100755 index 0000000000..34a5ac8269 --- /dev/null +++ b/src/dpp/dave/version.cpp @@ -0,0 +1,37 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#include "version.h" + +namespace dpp::dave { + +constexpr protocol_version current_dave_protocol_version = 1; + +protocol_version max_protocol_version() +{ + return current_dave_protocol_version; +} + +} // namespace dpp::dave + diff --git a/src/dpp/dave/version.h b/src/dpp/dave/version.h new file mode 100755 index 0000000000..6c554c2ef0 --- /dev/null +++ b/src/dpp/dave/version.h @@ -0,0 +1,48 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This folder is a modified fork of libdave, https://github.com/discord/libdave + * Copyright (c) 2024 Discord, Licensed under MIT + * + ************************************************************************************/ +#pragma once + +#include + +namespace dpp::dave { + +/** + * @brief Protocol Version ID + */ +using protocol_version = uint16_t; + +/** + * @brief Signature version ID + */ +using signature_version = uint8_t; + +/** + * @brief Get maximum supported protocol version + * @return maximum protocol version + */ +protocol_version max_protocol_version(); + +} // namespace dpp::dave + diff --git a/src/dpp/discordclient.cpp b/src/dpp/discordclient.cpp index 401d9cd610..09e5258ece 100644 --- a/src/dpp/discordclient.cpp +++ b/src/dpp/discordclient.cpp @@ -220,7 +220,7 @@ void discord_client::run() this->thread_id = runner->native_handle(); } -bool discord_client::handle_frame(const std::string &buffer) +bool discord_client::handle_frame(const std::string &buffer, ws_opcode opcode) { std::string& data = (std::string&)buffer; @@ -340,7 +340,7 @@ bool discord_client::handle_frame(const std::string &buffer) } } }; - this->write(jsonobj_to_string(obj)); + this->write(jsonobj_to_string(obj), protocol == ws_etf ? OP_BINARY : OP_TEXT); resumes++; } else { /* Full connect */ @@ -369,7 +369,7 @@ bool discord_client::handle_frame(const std::string &buffer) } } }; - this->write(jsonobj_to_string(obj)); + this->write(jsonobj_to_string(obj), protocol == ws_etf ? OP_BINARY : OP_TEXT); this->connect_time = creator->last_identify = time(nullptr); reconnects++; } @@ -459,6 +459,11 @@ void discord_client::log(dpp::loglevel severity, const std::string &msg) const dpp::log_t logmsg(nullptr, msg); logmsg.severity = severity; logmsg.message = msg; + size_t pos{0}; + while ((pos = logmsg.message.find(token, pos)) != std::string::npos) { + logmsg.message.replace(pos, token.length(), "*****"); + pos += 5; + } creator->on_log.call(logmsg); } } @@ -539,7 +544,7 @@ void discord_client::one_second_timer() ping_start = utility::time_f(); last_ping_message.clear(); } - this->write(message); + this->write(message, protocol == ws_etf ? OP_BINARY : OP_TEXT); } } @@ -608,7 +613,7 @@ uint64_t discord_client::get_channel_count() { return total; } -discord_client& discord_client::connect_voice(snowflake guild_id, snowflake channel_id, bool self_mute, bool self_deaf) { +discord_client& discord_client::connect_voice(snowflake guild_id, snowflake channel_id, bool self_mute, bool self_deaf, bool enable_dave) { #ifdef HAVE_VOICE std::unique_lock lock(voice_mutex); if (connecting_voice_channels.find(guild_id) != connecting_voice_channels.end()) { @@ -617,11 +622,11 @@ discord_client& discord_client::connect_voice(snowflake guild_id, snowflake chan return *this; } } - connecting_voice_channels[guild_id] = std::make_unique(this, channel_id); + connecting_voice_channels[guild_id] = std::make_unique(this, channel_id, enable_dave); /* Once sent, this expects two events (in any order) on the websocket: * VOICE_SERVER_UPDATE and VOICE_STATUS_UPDATE */ - log(ll_debug, "Sending op 4 to join VC, guild " + std::to_string(guild_id) + " channel " + std::to_string(channel_id)); + log(ll_debug, "Sending op 4 to join VC, guild " + std::to_string(guild_id) + " channel " + std::to_string(channel_id) + (enable_dave ? " WITH DAVE" : "")); queue_message(jsonobj_to_string(json({ { "op", 4 }, { "d", { @@ -684,7 +689,7 @@ voiceconn* discord_client::get_voice(snowflake guild_id) { } -voiceconn::voiceconn(discord_client* o, snowflake _channel_id) : creator(o), channel_id(_channel_id), voiceclient(nullptr) { +voiceconn::voiceconn(discord_client* o, snowflake _channel_id, bool enable_dave) : creator(o), channel_id(_channel_id), voiceclient(nullptr), dave(enable_dave) { } bool voiceconn::is_ready() { @@ -713,7 +718,7 @@ voiceconn& voiceconn::connect(snowflake guild_id) { auto t = std::thread([guild_id, this]() { try { this->creator->log(ll_debug, "Connecting voice for guild " + std::to_string(guild_id) + " channel " + std::to_string(this->channel_id)); - this->voiceclient = new discord_voice_client(creator->creator, this->channel_id, guild_id, this->token, this->session_id, this->websocket_hostname); + this->voiceclient = new discord_voice_client(creator->creator, this->channel_id, guild_id, this->token, this->session_id, this->websocket_hostname, this->dave); /* Note: Spawns thread! */ this->voiceclient->run(); } diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 43d0f954a8..ca44b19c06 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -20,43 +20,31 @@ * ************************************************************************************/ -#include -#include #ifdef _WIN32 #include #include #include #else - #include #include #include - #include - #include #include - #include #endif #include #include -#include #include #include #include -#include #include -#include -#include #include #ifdef HAVE_VOICE - #include - #include + #include "voice/enabled/enabled.h" #else - struct OpusDecoder {}; - struct OpusEncoder {}; - struct OpusRepacketizer {}; + #include "voice/stub/stub.h" #endif namespace dpp { + moving_averager::moving_averager(uint64_t collection_count_new) { collectionCount = collection_count_new; } @@ -77,324 +65,18 @@ moving_averager::operator float() { } return returnData / static_cast(values.size()); } - else { - return 0.0f; - } + return 0.0f; } -[[maybe_unused]] -constexpr int32_t opus_sample_rate_hz = 48000; -[[maybe_unused]] -constexpr int32_t opus_channel_count = 2; -std::string external_ip; - -/** - * @brief Represents an RTP packet. Size should always be exactly 12. - */ -struct rtp_header { - uint16_t constant; - uint16_t sequence; - uint32_t timestamp; - uint32_t ssrc; - - rtp_header(uint16_t _seq, uint32_t _ts, uint32_t _ssrc) : constant(htons(0x8078)), sequence(htons(_seq)), timestamp(htonl(_ts)), ssrc(htonl(_ssrc)) { - } -}; - bool discord_voice_client::sodium_initialised = false; -bool discord_voice_client::voice_payload::operator<(const voice_payload& other) const { - if (timestamp != other.timestamp) { - return timestamp > other.timestamp; - } - - constexpr rtp_seq_t wrap_around_test_boundary = 5000; - if ((seq < wrap_around_test_boundary && other.seq >= wrap_around_test_boundary) - || (seq >= wrap_around_test_boundary && other.seq < wrap_around_test_boundary)) { - /* Match the cases where exactly one of the sequence numbers "may have" - * wrapped around. - * - * Examples: - * 1. this->seq = 65530, other.seq = 10 // Did wrap around - * 2. this->seq = 5002, other.seq = 4990 // Not wrapped around - * - * Add 5000 to both sequence numbers to force wrap around so they can be - * compared. This should be fine to do to case 2 as well, as long as the - * addend (5000) is not too large to cause one of them to wrap around. - * - * In practice, we should be unlikely to hit the case where - * - * this->seq = 65530, other.seq = 5001 - * - * because we shouldn't receive more than 5000 payloads in one batch, unless - * the voice courier thread is super slow. Also remember that the timestamp - * is compared first, and payloads this far apart shouldn't have the same - * timestamp. - */ - - /* Casts here ensure the sum wraps around and not implicitly converted to - * wider types. - */ - return static_cast(seq + wrap_around_test_boundary) - > static_cast(other.seq + wrap_around_test_boundary); - } else { - return seq > other.seq; - } -} - -#ifdef HAVE_VOICE -size_t audio_mix(discord_voice_client& client, audio_mixer& mixer, opus_int32* pcm_mix, const opus_int16* pcm, size_t park_count, int samples, int& max_samples) { - /* Mix the combined stream if combined audio is bound */ - if (client.creator->on_voice_receive_combined.empty()) { - return 0; - } - - /* We must upsample the data to 32 bits wide, otherwise we could overflow */ - for (opus_int32 v = 0; v < (samples * opus_channel_count) / mixer.byte_blocks_per_register; ++v) { - mixer.combine_samples(pcm_mix, pcm); - pcm += mixer.byte_blocks_per_register; - pcm_mix += mixer.byte_blocks_per_register; - } - client.moving_average += park_count; - max_samples = (std::max)(samples, max_samples); - return park_count + 1; -} -#endif - -void discord_voice_client::voice_courier_loop(discord_voice_client& client, courier_shared_state_t& shared_state) { -#ifdef HAVE_VOICE - utility::set_thread_name(std::string("vcourier/") + std::to_string(client.server_id)); - while (true) { - std::this_thread::sleep_for(std::chrono::milliseconds{client.iteration_interval}); - - struct flush_data_t { - snowflake user_id; - rtp_seq_t min_seq; - std::priority_queue parked_payloads; - std::vector> pending_decoder_ctls; - std::shared_ptr decoder; - }; - std::vector flush_data; - - /* - * Transport the payloads onto this thread, and - * release the lock as soon as possible. - */ - { - std::unique_lock lk(shared_state.mtx); - - /* mitigates vector resizing while holding the mutex */ - flush_data.reserve(shared_state.parked_voice_payloads.size()); - - bool has_payload_to_deliver = false; - for (auto& [user_id, parking_lot] : shared_state.parked_voice_payloads) { - has_payload_to_deliver = has_payload_to_deliver || !parking_lot.parked_payloads.empty(); - flush_data.push_back(flush_data_t{user_id, - parking_lot.range.min_seq, - std::move(parking_lot.parked_payloads), - /* Quickly check if we already have a decoder and only take the pending ctls if so. */ - parking_lot.decoder ? std::move(parking_lot.pending_decoder_ctls) - : decltype(parking_lot.pending_decoder_ctls){}, - parking_lot.decoder}); - parking_lot.range.min_seq = parking_lot.range.max_seq + 1; - parking_lot.range.min_timestamp = parking_lot.range.max_timestamp + 1; - } - - if (!has_payload_to_deliver) { - if (shared_state.terminating) { - /* We have delivered all data to handlers. Terminate now. */ - break; - } - - shared_state.signal_iteration.wait(lk); - /* - * More data came or about to terminate, or just a spurious wake. - * We need to collect the payloads again to determine what to do next. - */ - continue; - } - } - - if (client.creator->on_voice_receive.empty() && client.creator->on_voice_receive_combined.empty()) { - /* - * We do this check late, to ensure this thread drains the data - * and prevents accumulating them even when there are no handlers. - */ - continue; - } - - /* This 32 bit PCM audio buffer is an upmixed version of the streams - * combined for all users. This is a wider width audio buffer so that - * there is no clipping when there are many loud audio sources at once. - */ - opus_int32 pcm_mix[23040] = { 0 }; - size_t park_count = 0; - int max_samples = 0; - int samples = 0; - - for (auto& d : flush_data) { - if (!d.decoder) { - continue; - } - for (const auto& decoder_ctl : d.pending_decoder_ctls) { - decoder_ctl(*d.decoder); - } - for (rtp_seq_t seq = d.min_seq; !d.parked_payloads.empty(); ++seq) { - opus_int16 pcm[23040]; - if (d.parked_payloads.top().seq != seq) { - /* - * Lost a packet with sequence number "seq", - * But Opus decoder might be able to guess something. - */ - if (int samples = opus_decode(d.decoder.get(), nullptr, 0, pcm, 5760, 0); - samples >= 0) { - /* - * Since this sample comes from a lost packet, - * we can only pretend there is an event, without any raw payload byte. - */ - voice_receive_t vr(nullptr, "", &client, d.user_id, reinterpret_cast(pcm), - samples * opus_channel_count * sizeof(opus_int16)); - - park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); - client.creator->on_voice_receive.call(vr); - } - } else { - voice_receive_t& vr = *d.parked_payloads.top().vr; - if (vr.audio_data.size() > 0x7FFFFFFF) { - throw dpp::length_exception(err_massive_audio, "audio_data > 2GB! This should never happen!"); - } - if (samples = opus_decode(d.decoder.get(), vr.audio_data.data(), - static_cast(vr.audio_data.size() & 0x7FFFFFFF), pcm, 5760, 0); - samples >= 0) { - vr.reassign(&client, d.user_id, reinterpret_cast(pcm), - samples * opus_channel_count * sizeof(opus_int16)); - client.end_gain = 1.0f / client.moving_average; - park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); - client.creator->on_voice_receive.call(vr); - } - - d.parked_payloads.pop(); - } - } - } - - /* If combined receive is bound, dispatch it */ - if (park_count) { - - /* Downsample the 32 bit samples back to 16 bit */ - opus_int16 pcm_downsample[23040] = { 0 }; - opus_int16* pcm_downsample_ptr = pcm_downsample; - opus_int32* pcm_mix_ptr = pcm_mix; - client.increment = (client.end_gain - client.current_gain) / static_cast(samples); - for (int64_t x = 0; x < (samples * opus_channel_count) / client.mixer->byte_blocks_per_register; ++x) { - client.mixer->collect_single_register(pcm_mix_ptr, pcm_downsample_ptr, client.current_gain, client.increment); - client.current_gain += client.increment * static_cast(client.mixer->byte_blocks_per_register); - pcm_mix_ptr += client.mixer->byte_blocks_per_register; - pcm_downsample_ptr += client.mixer->byte_blocks_per_register; - } - - voice_receive_t vr(nullptr, "", &client, 0, reinterpret_cast(pcm_downsample), - max_samples * opus_channel_count * sizeof(opus_int16)); - - client.creator->on_voice_receive_combined.call(vr); - } - } -#endif -} - -discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host) - : websocket_client(_host.substr(0, _host.find(":")), _host.substr(_host.find(":") + 1, _host.length()), "/?v=8", OP_TEXT), - runner(nullptr), - connect_time(0), - mixer(std::make_unique()), - port(0), - ssrc(0), - timescale(1000000), - paused(false), - encoder(nullptr), - repacketizer(nullptr), - fd(INVALID_SOCKET), - secret_key(nullptr), - sequence(0), - timestamp(0), - packet_nonce(1), - last_timestamp(std::chrono::high_resolution_clock::now()), - sending(false), - tracks(0), - creator(_cluster), - terminating(false), - heartbeat_interval(0), - last_heartbeat(time(nullptr)), - token(_token), - sessionid(_session_id), - server_id(_server_id), - channel_id(_channel_id) -{ -#if HAVE_VOICE - if (!discord_voice_client::sodium_initialised) { - if (sodium_init() < 0) { - throw dpp::voice_exception(err_sodium, "discord_voice_client::discord_voice_client; sodium_init() failed"); - } - discord_voice_client::sodium_initialised = true; - } - int opusError = 0; - encoder = opus_encoder_create(opus_sample_rate_hz, opus_channel_count, OPUS_APPLICATION_VOIP, &opusError); - if (opusError) { - throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_encoder_create() failed"); - } - repacketizer = opus_repacketizer_create(); - if (!repacketizer) { - throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_repacketizer_create() failed"); - } - try { - this->connect(); - } - catch (std::exception&) { - cleanup(); - throw; - } -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif -} - discord_voice_client::~discord_voice_client() { cleanup(); } -void discord_voice_client::cleanup() -{ - if (runner) { - this->terminating = true; - runner->join(); - delete runner; - runner = nullptr; - } -#if HAVE_VOICE - if (encoder) { - opus_encoder_destroy(encoder); - encoder = nullptr; - } - if (repacketizer) { - opus_repacketizer_destroy(repacketizer); - repacketizer = nullptr; - } - if (voice_courier.joinable()) { - { - std::lock_guard lk(voice_courier_shared_state.mtx); - voice_courier_shared_state.terminating = true; - } - voice_courier_shared_state.signal_iteration.notify_one(); - voice_courier.join(); - } -#endif - delete[] secret_key; - secret_key = nullptr; -} - bool discord_voice_client::is_ready() { - return secret_key != nullptr; + return has_secret_key; } bool discord_voice_client::is_playing() { @@ -402,271 +84,61 @@ bool discord_voice_client::is_playing() { return (!this->outbuf.empty()); } -void discord_voice_client::thread_run() -{ - utility::set_thread_name(std::string("vc/") + std::to_string(server_id)); - - size_t times_looped = 0; - time_t last_loop_time = time(nullptr); - - do { - bool error = false; - ssl_client::read_loop(); - ssl_client::close(); - - time_t current_time = time(nullptr); - /* Here, we check if it's been longer than 3 seconds since the previous loop, - * this gives us time to see if it's an actual disconnect, or an error. - * This will prevent us from looping too much, meaning error codes do not cause an infinite loop. - */ - if (current_time - last_loop_time >= 3) - times_looped = 0; - - /* This does mean we'll always have times_looped at a minimum of 1, this is intended. */ - times_looped++; - /* If we've looped 5 or more times, abort the loop. */ - if (times_looped >= 5) { - log(dpp::ll_warning, "Reached max loops whilst attempting to read from the websocket. Aborting websocket."); - break; - } - - last_loop_time = current_time; - - if (!terminating) { - log(dpp::ll_debug, "Attempting to reconnect the websocket..."); - do { - try { - ssl_client::connect(); - websocket_client::connect(); - } - catch (const std::exception &e) { - log(dpp::ll_error, std::string("Error establishing voice websocket connection, retry in 5 seconds: ") + e.what()); - ssl_client::close(); - std::this_thread::sleep_for(std::chrono::seconds(5)); - error = true; - } - } while (error && !terminating); - } - } while(!terminating); +uint16_t dave_binary_header_t::get_transition_id() const { + if (opcode != voice_client_dave_mls_welcome) { + throw dpp::logic_exception("Can't get transition ID from buffer that is not of type voice_client_dave_mls_welcome(30)"); + } + return transition_id; } -void discord_voice_client::run() -{ - this->runner = new std::thread(&discord_voice_client::thread_run, this); - this->thread_id = runner->native_handle(); +dave_binary_header_t::dave_binary_header_t(const std::string& buffer) { + if (buffer.length() < 5) { + throw dpp::length_exception("DAVE binary buffer too short (<5)"); + } + seq = (buffer[0] << 8) | buffer[1]; + opcode = buffer[2]; + transition_id = (buffer[3] << 8) | buffer[4]; + package.assign(buffer.begin() + (opcode == voice_client_dave_mls_welcome ? 5 : 3), buffer.end()); } -int discord_voice_client::udp_send(const char* data, size_t length) -{ - sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(this->port); - servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); - return (int) sendto(this->fd, data, (int)length, 0, (const sockaddr*)&servaddr, (int)sizeof(sockaddr_in)); +std::vector dave_binary_header_t::get_data() const { + return package; } -int discord_voice_client::udp_recv(char* data, size_t max_length) -{ - return (int) recv(this->fd, data, (int)max_length, 0); +std::string discord_voice_client::get_privacy_code() const { +#ifdef HAVE_VOICE + return is_end_to_end_encrypted() ? mls_state->privacy_code : ""; +#else + return ""; +#endif } -bool discord_voice_client::handle_frame(const std::string &data) -{ - log(dpp::ll_trace, std::string("R: ") + data); - json j; - - try { - j = json::parse(data); - } - catch (const std::exception &e) { - log(dpp::ll_error, std::string("discord_voice_client::handle_frame ") + e.what() + ": " + data); - return true; +void discord_voice_client::get_user_privacy_code(const dpp::snowflake user, privacy_code_callback_t callback) const { +#ifdef HAVE_VOICE + if (!is_end_to_end_encrypted()) { + callback(""); + return; } + mls_state->dave_session->get_pairwise_fingerprint(0x0000, user.str(), [callback](const std::vector &data) { + callback(data.size() == 64 ? generate_displayable_code(data, 45) : ""); + }); +#else + callback(""); +#endif +} - if (j.find("op") != j.end()) { - uint32_t op = j["op"]; - - switch (op) { - /* Client Disconnect */ - case 13: { - if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null()) { - snowflake u_id = snowflake_not_null(&j["d"], "user_id"); - auto it = std::find_if(ssrc_map.begin(), ssrc_map.end(), - [&u_id](const auto & p) { return p.second == u_id; }); - - if (it != ssrc_map.end()) { - ssrc_map.erase(it); - } - - if (!creator->on_voice_client_disconnect.empty()) { - voice_client_disconnect_t vcd(nullptr, data); - vcd.voice_client = this; - vcd.user_id = u_id; - creator->on_voice_client_disconnect.call(vcd); - } - } - } - break; - /* Speaking */ - case 5: - /* Client Connect (doesn't seem to work) */ - case 12: { - if (j.find("d") != j.end() - && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null() - && j["d"].find("ssrc") != j["d"].end() && !j["d"]["ssrc"].is_null() && j["d"]["ssrc"].is_number_integer()) { - uint32_t u_ssrc = j["d"]["ssrc"].get(); - snowflake u_id = snowflake_not_null(&j["d"], "user_id"); - ssrc_map[u_ssrc] = u_id; - - if (!creator->on_voice_client_speaking.empty()) { - voice_client_speaking_t vcs(nullptr, data); - vcs.voice_client = this; - vcs.user_id = u_id; - vcs.ssrc = u_ssrc; - creator->on_voice_client_speaking.call(vcs); - } - } - } - break; - /* Voice resume */ - case 9: - log(ll_debug, "Voice connection resumed"); - break; - /* Voice HELLO */ - case 8: { - if (j.find("d") != j.end() && j["d"].find("heartbeat_interval") != j["d"].end() && !j["d"]["heartbeat_interval"].is_null()) { - this->heartbeat_interval = j["d"]["heartbeat_interval"].get(); - } - - if (!modes.empty()) { - log(dpp::ll_debug, "Resuming voice session..."); - json obj = { - { "op", 7 }, - { - "d", - { - { "server_id", std::to_string(this->server_id) }, - { "session_id", this->sessionid }, - { "token", this->token }, - } - } - }; - this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace)); - } else { - log(dpp::ll_debug, "Connecting new voice session..."); - json obj = { - { "op", 0 }, - { - "d", - { - { "user_id", creator->me.id }, - { "server_id", std::to_string(this->server_id) }, - { "session_id", this->sessionid }, - { "token", this->token }, - } - } - }; - this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace)); - } - this->connect_time = time(nullptr); - } - break; - /* Session description */ - case 4: { - json &d = j["d"]; - secret_key = new uint8_t[32]; - size_t ofs = 0; - for (auto & c : d["secret_key"]) { - *(secret_key + ofs) = (uint8_t)c; - ofs++; - if (ofs > 31) { - break; - } - } - - /* This is needed to start voice receiving and make sure that the start of sending isn't cut off */ - send_silence(20); - - /* Fire on_voice_ready */ - if (!creator->on_voice_ready.empty()) { - voice_ready_t rdy(nullptr, data); - rdy.voice_client = this; - rdy.voice_channel_id = this->channel_id; - creator->on_voice_ready.call(rdy); - } - - /* Reset packet_nonce */ - packet_nonce = 1; - } - break; - /* Voice ready */ - case 2: { - /* Video stream stuff comes in this frame too, but we can't use it (YET!) */ - json &d = j["d"]; - this->ip = d["ip"].get(); - this->port = d["port"].get(); - this->ssrc = d["ssrc"].get(); - // Modes - for (auto & m : d["modes"]) { - this->modes.push_back(m.get()); - } - log(ll_debug, "Voice websocket established; UDP endpoint: " + ip + ":" + std::to_string(port) + " [ssrc=" + std::to_string(ssrc) + "] with " + std::to_string(modes.size()) + " modes"); - - external_ip = discover_ip(); - - dpp::socket newfd; - if ((newfd = ::socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { - - sockaddr_in servaddr{}; - memset(&servaddr, 0, sizeof(sockaddr_in)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(0); - - if (bind(newfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) { - throw dpp::connection_exception(err_bind_failure, "Can't bind() client UDP socket"); - } - - if (!set_nonblocking(newfd, true)) { - throw dpp::connection_exception(err_nonblocking_failure, "Can't switch voice UDP socket to non-blocking mode!"); - } - - /* Hook poll() in the ssl_client to add a new file descriptor */ - this->fd = newfd; - this->custom_writeable_fd = std::bind(&discord_voice_client::want_write, this); - this->custom_readable_fd = std::bind(&discord_voice_client::want_read, this); - this->custom_writeable_ready = std::bind(&discord_voice_client::write_ready, this); - this->custom_readable_ready = std::bind(&discord_voice_client::read_ready, this); - - int bound_port = 0; - sockaddr_in sin; - socklen_t len = sizeof(sin); - if (getsockname(this->fd, (sockaddr *)&sin, &len) > -1) { - bound_port = ntohs(sin.sin_port); - } +bool discord_voice_client::is_end_to_end_encrypted() const { +#ifdef HAVE_VOICE + if (mls_state == nullptr) { + return false; + } - log(ll_debug, "External IP address: " + external_ip); + bool has_pending_downgrade = mls_state->pending_transition.is_pending && mls_state->pending_transition.protocol_version != dave_version_1; - this->write(json({ - { "op", 1 }, - { "d", { - { "protocol", "udp" }, - { "data", { - { "address", external_ip }, - { "port", bound_port }, - { "mode", "aead_xchacha20_poly1305_rtpsize" } - } - } - } - } - }).dump(-1, ' ', false, json::error_handler_t::replace)); - } - } - break; - } - } - return true; + return !has_pending_downgrade && !mls_state->privacy_code.empty(); +#else + return false; +#endif } discord_voice_client& discord_voice_client::pause_audio(bool pause) { @@ -702,259 +174,6 @@ discord_voice_client& discord_voice_client::stop_audio() { return *this; } -void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { - std::lock_guard lock(this->stream_mutex); - voice_out_packet frame; - frame.packet = std::string(packet, len); - frame.duration = duration; - outbuf.emplace_back(frame); -} - -void discord_voice_client::read_ready() -{ -#ifdef HAVE_VOICE - uint8_t buffer[65535]; - int packet_size = this->udp_recv((char*)buffer, sizeof(buffer)); - - bool receive_handler_is_empty = creator->on_voice_receive.empty() && creator->on_voice_receive_combined.empty(); - if (packet_size <= 0 || receive_handler_is_empty) { - /* Nothing to do */ - return; - } - - constexpr size_t header_size = 12; - if (static_cast(packet_size) < header_size) { - /* Invalid RTP payload */ - return; - } - - /* It's a "silence packet" - throw it away. */ - if (packet_size < 44) { - return; - } - - if (uint8_t payload_type = buffer[1] & 0b0111'1111; - 72 <= payload_type && payload_type <= 76) { - /* - * This is an RTCP payload. Discord is known to send - * RTCP Receiver Reports. - * - * See https://datatracker.ietf.org/doc/html/rfc3551#section-6 - */ - return; - } - - voice_payload vp{0, // seq, populate later - 0, // timestamp, populate later - std::make_unique(nullptr, std::string((char*)buffer, packet_size))}; - - vp.vr->voice_client = this; - - uint32_t speaker_ssrc; - { /* Get the User ID of the speaker */ - std::memcpy(&speaker_ssrc, &buffer[8], sizeof(uint32_t)); - speaker_ssrc = ntohl(speaker_ssrc); - vp.vr->user_id = ssrc_map[speaker_ssrc]; - } - - /* Get the sequence number of the voice UDP packet */ - std::memcpy(&vp.seq, &buffer[2], sizeof(rtp_seq_t)); - vp.seq = ntohs(vp.seq); - /* Get the timestamp of the voice UDP packet */ - std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); - vp.timestamp = ntohl(vp.timestamp); - - constexpr size_t nonce_size = sizeof(uint32_t); - /* Nonce is 4 byte at the end of payload with zero padding */ - uint8_t nonce[24] = { 0 }; - std::memcpy(nonce, buffer + packet_size - nonce_size, nonce_size); - - /* Get the number of CSRC in header */ - const size_t csrc_count = buffer[0] & 0b0000'1111; - /* Skip to the encrypted voice data */ - const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; - size_t total_header_len = offset_to_data; - - uint8_t* ciphertext = buffer + offset_to_data; - size_t ciphertext_len = packet_size - offset_to_data - nonce_size; - - size_t ext_len = 0; - if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - /** - * Get the RTP Extensions size, we only get the size here because - * the extension itself is encrypted along with the opus packet - */ - { - uint16_t ext_len_in_words; - memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); - ext_len_in_words = ntohs(ext_len_in_words); - ext_len = sizeof(uint32_t) * ext_len_in_words; - } - constexpr size_t ext_header_len = sizeof(uint16_t) * 2; - ciphertext += ext_header_len; - ciphertext_len -= ext_header_len; - total_header_len += ext_header_len; - } - - uint8_t decrypted[65535] = { 0 }; - unsigned long long opus_packet_len = 0; - if (crypto_aead_xchacha20poly1305_ietf_decrypt( - decrypted, &opus_packet_len, - nullptr, - ciphertext, ciphertext_len, - buffer, - /** - * Additional Data: - * The whole header (including csrc list) + - * 4 byte extension header (magic 0xBEDE + 16-bit denoting extension length) - */ - total_header_len, - nonce, secret_key) != 0) { - /* Invalid Discord RTP payload. */ - return; - } - - uint8_t *opus_packet = decrypted; - if (ext_len > 0) { - /* Skip previously encrypted RTP Header Extension */ - opus_packet += ext_len; - opus_packet_len -= ext_len; - } - - /* - * We're left with the decrypted, opus-encoded data. - * Park the payload and decode on the voice courier thread. - */ - vp.vr->audio_data.assign(opus_packet, opus_packet + opus_packet_len); - - { - std::lock_guard lk(voice_courier_shared_state.mtx); - auto& [range, payload_queue, pending_decoder_ctls, decoder] = voice_courier_shared_state.parked_voice_payloads[vp.vr->user_id]; - - if (!decoder) { - /* - * Most likely this is the first time we encounter this speaker. - * Do some initialization for not only the decoder but also the range. - */ - range.min_seq = vp.seq; - range.min_timestamp = vp.timestamp; - - int opus_error = 0; - decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), - &opus_decoder_destroy); - if (opus_error) { - /** - * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, - * which would otherwise conflict as every C library loves to use values from -1 downwards. - */ - throw dpp::voice_exception((exception_error_code)(opus_error - 10), "discord_voice_client::discord_voice_client; opus_decoder_create() failed"); - } - } - - if (vp.seq < range.min_seq && vp.timestamp < range.min_timestamp) { - /* This packet arrived too late. We can only discard it. */ - return; - } - range.max_seq = vp.seq; - range.max_timestamp = vp.timestamp; - payload_queue.push(std::move(vp)); - } - - voice_courier_shared_state.signal_iteration.notify_one(); - - if (!voice_courier.joinable()) { - /* Courier thread is not running, start it */ - voice_courier = std::thread(&voice_courier_loop, - std::ref(*this), - std::ref(voice_courier_shared_state)); - } -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif -} - -void discord_voice_client::write_ready() -{ - uint64_t duration = 0; - bool track_marker_found = false; - uint64_t bufsize = 0; - send_audio_type_t type = satype_recorded_audio; - { - std::lock_guard lock(this->stream_mutex); - if (!this->paused && outbuf.size()) { - type = send_audio_type; - if (outbuf[0].packet.size() == sizeof(uint16_t) && (*((uint16_t*)(outbuf[0].packet.data()))) == AUDIO_TRACK_MARKER) { - outbuf.erase(outbuf.begin()); - track_marker_found = true; - if (tracks > 0) { - tracks--; - } - } - if (outbuf.size()) { - if (this->udp_send(outbuf[0].packet.data(), outbuf[0].packet.length()) == (int)outbuf[0].packet.length()) { - duration = outbuf[0].duration * timescale; - bufsize = outbuf[0].packet.length(); - outbuf.erase(outbuf.begin()); - } - } - } - } - if (duration) { - if (type == satype_recorded_audio) { - std::chrono::nanoseconds latency = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - last_timestamp); - std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) - latency; - if (sleep_time.count() > 0) { - std::this_thread::sleep_for(sleep_time); - } - } - else if (type == satype_overlap_audio) { - std::chrono::nanoseconds latency = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - last_timestamp); - std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) + last_sleep_remainder - latency; - std::chrono::nanoseconds sleep_increment = (std::chrono::nanoseconds(duration) - latency) / AUDIO_OVERLAP_SLEEP_SAMPLES; - if (sleep_time.count() > 0) { - uint16_t samples_count = 0; - std::chrono::nanoseconds overshoot_accumulator{}; - - do { - std::chrono::high_resolution_clock::time_point start_sleep = std::chrono::high_resolution_clock::now(); - std::this_thread::sleep_for(sleep_increment); - std::chrono::high_resolution_clock::time_point end_sleep = std::chrono::high_resolution_clock::now(); - - samples_count++; - overshoot_accumulator += std::chrono::duration_cast(end_sleep - start_sleep) - sleep_increment; - sleep_time -= std::chrono::duration_cast(end_sleep - start_sleep); - } while (std::chrono::nanoseconds(overshoot_accumulator.count() / samples_count) + sleep_increment < sleep_time); - last_sleep_remainder = sleep_time; - } else { - last_sleep_remainder = std::chrono::nanoseconds(0); - } - } - - last_timestamp = std::chrono::high_resolution_clock::now(); - if (!creator->on_voice_buffer_send.empty()) { - voice_buffer_send_t snd(nullptr, ""); - snd.buffer_size = bufsize; - snd.packets_left = outbuf.size(); - snd.voice_client = this; - creator->on_voice_buffer_send.call(snd); - } - } - if (track_marker_found) { - if (!creator->on_voice_track_marker.empty()) { - voice_track_marker_t vtm(nullptr, ""); - vtm.voice_client = this; - { - std::lock_guard lock(this->stream_mutex); - if (!track_meta.empty()) { - vtm.track_meta = track_meta[0]; - track_meta.erase(track_meta.begin()); - } - } - creator->on_voice_track_marker.call(vtm); - } - } -} - dpp::utility::uptime discord_voice_client::get_uptime() { return dpp::utility::uptime(time(nullptr) - connect_time); @@ -965,19 +184,6 @@ bool discord_voice_client::is_connected() return (this->get_state() == CONNECTED); } -dpp::socket discord_voice_client::want_write() { - std::lock_guard lock(this->stream_mutex); - if (!this->paused && !outbuf.empty()) { - return fd; - } else { - return INVALID_SOCKET; - } -} - -dpp::socket discord_voice_client::want_read() { - return fd; -} - void discord_voice_client::error(uint32_t errorcode) { const static std::map errortext = { @@ -1112,70 +318,28 @@ void discord_voice_client::one_second_timer() if (!message_queue.empty()) { std::string message = message_queue.front(); message_queue.pop_front(); - this->write(message); + this->write(message, OP_TEXT); } } if (this->heartbeat_interval) { /* Check if we're due to emit a heartbeat */ if (time(nullptr) > last_heartbeat + ((heartbeat_interval / 1000.0) * 0.75)) { - queue_message(json({{"op", 3}, {"d", rand()}}).dump(-1, ' ', false, json::error_handler_t::replace), true); + queue_message(json({ + {"op", voice_opcode_connection_heartbeat}, + { + "d", { + {"t", rand()}, + {"seq_ack", receive_sequence}, + } + }, + }).dump(-1, ' ', false, json::error_handler_t::replace), true); last_heartbeat = time(nullptr); } } } } -size_t discord_voice_client::encode(uint8_t *input, size_t inDataSize, uint8_t *output, size_t &outDataSize) -{ -#if HAVE_VOICE - outDataSize = 0; - int mEncFrameBytes = 11520; - int mEncFrameSize = 2880; - if (0 == (inDataSize % mEncFrameBytes)) { - bool isOk = true; - uint8_t *out = encode_buffer; - - memset(out, 0, sizeof(encode_buffer)); - repacketizer = opus_repacketizer_init(repacketizer); - if (!repacketizer) { - log(ll_warning, "opus_repacketizer_init(): failure"); - return outDataSize; - } - for (size_t i = 0; i < (inDataSize / mEncFrameBytes); ++ i) { - const opus_int16* pcm = (opus_int16*)(input + i * mEncFrameBytes); - int ret = opus_encode(encoder, pcm, mEncFrameSize, out, 65536); - if (ret > 0) { - int retval = opus_repacketizer_cat(repacketizer, out, ret); - if (retval != OPUS_OK) { - isOk = false; - log(ll_warning, "opus_repacketizer_cat(): " + std::string(opus_strerror(retval))); - break; - } - out += ret; - } else { - isOk = false; - log(ll_warning, "opus_encode(): " + std::string(opus_strerror(ret))); - break; - } - } - if (isOk) { - int ret = opus_repacketizer_out(repacketizer, output, 65536); - if (ret > 0) { - outDataSize = ret; - } else { - log(ll_warning, "opus_repacketizer_out(): " + std::string(opus_strerror(ret))); - } - } - } else { - throw dpp::voice_exception(err_invalid_voice_packet_length, "Invalid input data length: " + std::to_string(inDataSize) + ", must be n times of " + std::to_string(mEncFrameBytes)); - } -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif - return outDataSize; -} - discord_voice_client& discord_voice_client::insert_marker(const std::string& metadata) { /* Insert a track marker. A track marker is a single 16 bit value of 0xFFFF. * This is too small to be a valid RTP packet so the send function knows not @@ -1236,131 +400,15 @@ discord_voice_client& discord_voice_client::send_silence(const uint64_t duration discord_voice_client& discord_voice_client::set_send_audio_type(send_audio_type_t type) { - { - std::lock_guard lock(this->stream_mutex); - send_audio_type = type; - } - return *this; -} - -discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, const size_t length) { -#if HAVE_VOICE - if (length < 4) { - throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size can't be less than 4"); - } - - if ((length % 4) != 0) { - throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size should be divisible by 4"); - } - - if (length > send_audio_raw_max_length) { - std::string s_audio_data((const char*)audio_data, length); - - while (s_audio_data.length() > send_audio_raw_max_length) { - std::string packet(s_audio_data.substr(0, send_audio_raw_max_length)); - const auto packet_size = static_cast(packet.size()); - - s_audio_data.erase(s_audio_data.begin(), s_audio_data.begin() + packet_size); - - send_audio_raw((uint16_t*)packet.data(), packet_size); - } - - return *this; - } - - if (length < send_audio_raw_max_length) { - std::string packet((const char*)audio_data, length); - packet.resize(send_audio_raw_max_length, 0); - - return send_audio_raw((uint16_t*)packet.data(), packet.size()); - } - - opus_int32 encoded_audio_max_length = (opus_int32)length; - std::vector encoded_audio(encoded_audio_max_length); - size_t encoded_audio_length = encoded_audio_max_length; - - encoded_audio_length = this->encode((uint8_t*)audio_data, length, encoded_audio.data(), encoded_audio_length); - - send_audio_opus(encoded_audio.data(), encoded_audio_length); -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif - return *this; -} - -discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length) { -#if HAVE_VOICE - int samples = opus_packet_get_nb_samples(opus_packet, (opus_int32)length, opus_sample_rate_hz); - uint64_t duration = (samples / 48) / (timescale / 1000000); - send_audio_opus(opus_packet, length, duration); -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif - return *this; -} - -discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { -#if HAVE_VOICE - int frame_size = (int)(48 * duration * (timescale / 1000000)); - opus_int32 encoded_audio_max_length = (opus_int32)length; - std::vector encoded_audio(encoded_audio_max_length); - size_t encoded_audio_length = encoded_audio_max_length; - - encoded_audio_length = length; - encoded_audio.reserve(length); - memcpy(encoded_audio.data(), opus_packet, length); - - ++sequence; - rtp_header header(sequence, timestamp, (uint32_t)ssrc); - - /* Expected payload size is unencrypted header + encrypted opus packet + unencrypted 32 bit nonce */ - size_t packet_siz = sizeof(header) + (encoded_audio_length + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); - - std::vector payload(packet_siz); - - /* Set RTP header */ - std::memcpy(payload.data(), &header, sizeof(header)); - - /* Convert nonce to big-endian */ - uint32_t noncel = htonl(packet_nonce); - - /* 24 byte is needed for encrypting, discord just want 4 byte so just fill up the rest with null */ - unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { '\0' }; - memcpy(encrypt_nonce, &noncel, sizeof(noncel)); - - /* Execute */ - crypto_aead_xchacha20poly1305_ietf_encrypt( - payload.data() + sizeof(header), - nullptr, - encoded_audio.data(), - encoded_audio_length, - /* The RTP Header as Additional Data */ - reinterpret_cast(&header), - sizeof(header), - nullptr, - static_cast(encrypt_nonce), - secret_key); - - /* Append the 4 byte nonce to the resulting payload */ - std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); - - this->send(reinterpret_cast(payload.data()), payload.size(), duration); - timestamp += frame_size; - - /* Increment for next packet */ - packet_nonce++; - - speak(); -#else - throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); -#endif + std::lock_guard lock(this->stream_mutex); + send_audio_type = type; return *this; } discord_voice_client& discord_voice_client::speak() { if (!this->sending) { this->queue_message(json({ - {"op", 5}, + {"op", voice_opcode_client_speaking}, {"d", { {"speaking", 1}, {"delay", 0}, @@ -1381,47 +429,6 @@ uint64_t discord_voice_client::get_timescale() { return timescale; } -std::string discord_voice_client::discover_ip() { - dpp::socket newfd = SOCKET_ERROR; - unsigned char packet[74] = { 0 }; - (*(uint16_t*)(packet)) = htons(0x01); - (*(uint16_t*)(packet + 2)) = htons(70); - (*(uint32_t*)(packet + 4)) = htonl((uint32_t)this->ssrc); - if ((newfd = ::socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { - sockaddr_in servaddr{}; - memset(&servaddr, 0, sizeof(sockaddr_in)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(0); - if (bind(newfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) { - log(ll_warning, "Could not bind socket for IP discovery"); - return ""; - } - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(this->port); - servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); - if (::connect(newfd, (const sockaddr*)&servaddr, sizeof(sockaddr_in)) < 0) { - log(ll_warning, "Could not connect socket for IP discovery"); - return ""; - } - if (::send(newfd, (const char*)packet, 74, 0) == -1) { - log(ll_warning, "Could not send packet for IP discovery"); - return ""; - } - if (recv(newfd, (char*)packet, 74, 0) == -1) { - log(ll_warning, "Could not receive packet for IP discovery"); - return ""; - } - - close_socket(newfd); - - //utility::debug_dump(packet, 74); - return std::string((const char*)(packet + 8)); - } - return ""; -} - discord_voice_client& discord_voice_client::set_iteration_interval(uint16_t interval) { this->iteration_interval = interval; return *this; diff --git a/src/dpp/guild.cpp b/src/dpp/guild.cpp index a4040e2a99..7751d6abea 100644 --- a/src/dpp/guild.cpp +++ b/src/dpp/guild.cpp @@ -948,7 +948,7 @@ permission guild::permission_overwrites(const guild_member &member, const channe return permissions; } -bool guild::connect_member_voice(snowflake user_id, bool self_mute, bool self_deaf) { +bool guild::connect_member_voice(snowflake user_id, bool self_mute, bool self_deaf, bool dave) { for (auto & c : channels) { channel* ch = dpp::find_channel(c); if (!ch || (!ch->is_voice_channel() && !ch->is_stage_channel())) { @@ -958,7 +958,7 @@ bool guild::connect_member_voice(snowflake user_id, bool self_mute, bool self_de auto vsi = vcmembers.find(user_id); if (vsi != vcmembers.end()) { if (vsi->second.shard) { - vsi->second.shard->connect_voice(this->id, vsi->second.channel_id, self_mute, self_deaf); + vsi->second.shard->connect_voice(this->id, vsi->second.channel_id, self_mute, self_deaf, dave); return true; } } diff --git a/src/dpp/httpsclient.cpp b/src/dpp/httpsclient.cpp index 5d56f43a5c..9ac8faa021 100644 --- a/src/dpp/httpsclient.cpp +++ b/src/dpp/httpsclient.cpp @@ -58,7 +58,7 @@ void https_client::connect() map_headers += k + ": " + v + "\r\n"; } if (this->sfd != SOCKET_ERROR) { - this->write( + this->socket_write( this->request_type + " " + this->path + " HTTP/" + http_protocol + "\r\n" "Host: " + this->hostname + "\r\n" "pragma: no-cache\r\n" diff --git a/src/dpp/sslclient.cpp b/src/dpp/sslclient.cpp index e66dd1204a..d1f15ac20a 100644 --- a/src/dpp/sslclient.cpp +++ b/src/dpp/sslclient.cpp @@ -379,7 +379,7 @@ void ssl_client::connect() } } -void ssl_client::write(const std::string_view data) +void ssl_client::socket_write(const std::string_view data) { /* If we are in nonblocking mode, append to the buffer, * otherwise just use SSL_write directly. The only time we diff --git a/src/dpp/utility.cpp b/src/dpp/utility.cpp index 0b07ec0e8f..b41be262fa 100644 --- a/src/dpp/utility.cpp +++ b/src/dpp/utility.cpp @@ -355,25 +355,25 @@ image_data&& icon::as_image_data() && { return std::move(std::get(hash_or_data)); } -std::string debug_dump(uint8_t* data, size_t length) { +std::string debug_dump(const uint8_t* data, size_t length) { std::ostringstream out; size_t addr = (size_t)data; size_t extra = addr % 16; if (extra != 0) { addr -= extra; - out << to_hex(addr); + out << "\n[" << to_hex(addr) << "] : "; } for (size_t n = 0; n < extra; ++n) { out << "-- "; } std::string ascii; - for (uint8_t* ptr = data; ptr < data + length; ++ptr) { + for (const uint8_t* ptr = data; ptr < data + length; ++ptr) { if (((size_t)ptr % 16) == 0) { out << ascii << "\n[" << to_hex((size_t)ptr) << "] : "; ascii.clear(); } ascii.push_back(*ptr >= ' ' && *ptr <= '~' ? *ptr : '.'); - out << to_hex(*ptr); + out << to_hex(*ptr) << " "; } out << " " << ascii; out << "\n"; diff --git a/src/dpp/voice/enabled/audio_mix.cpp b/src/dpp/voice/enabled/audio_mix.cpp new file mode 100644 index 0000000000..a411623f6d --- /dev/null +++ b/src/dpp/voice/enabled/audio_mix.cpp @@ -0,0 +1,55 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace dpp { + +size_t audio_mix(discord_voice_client &client, audio_mixer &mixer, opus_int32 *pcm_mix, const opus_int16 *pcm, size_t park_count, int samples, int &max_samples) { + /* Mix the combined stream if combined audio is bound */ + if (client.creator->on_voice_receive_combined.empty()) { + return 0; + } + + /* We must upsample the data to 32 bits wide, otherwise we could overflow */ + for (opus_int32 v = 0; v < (samples * opus_channel_count) / mixer.byte_blocks_per_register; ++v) { + mixer.combine_samples(pcm_mix, pcm); + pcm += mixer.byte_blocks_per_register; + pcm_mix += mixer.byte_blocks_per_register; + } + client.moving_average += park_count; + max_samples = (std::max)(samples, max_samples); + return park_count + 1; +} + +}; diff --git a/src/dpp/voice/enabled/cleanup.cpp b/src/dpp/voice/enabled/cleanup.cpp new file mode 100644 index 0000000000..838000e884 --- /dev/null +++ b/src/dpp/voice/enabled/cleanup.cpp @@ -0,0 +1,62 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +void discord_voice_client::cleanup() +{ + if (runner) { + this->terminating = true; + runner->join(); + delete runner; + runner = nullptr; + } + if (encoder) { + opus_encoder_destroy(encoder); + encoder = nullptr; + } + if (repacketizer) { + opus_repacketizer_destroy(repacketizer); + repacketizer = nullptr; + } + if (voice_courier.joinable()) { + { + std::lock_guard lk(voice_courier_shared_state.mtx); + voice_courier_shared_state.terminating = true; + } + voice_courier_shared_state.signal_iteration.notify_one(); + voice_courier.join(); + } +} + +} diff --git a/src/dpp/voice/enabled/constructor.cpp b/src/dpp/voice/enabled/constructor.cpp new file mode 100644 index 0000000000..1e0a20b8f3 --- /dev/null +++ b/src/dpp/voice/enabled/constructor.cpp @@ -0,0 +1,91 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host, bool enable_dave) + : websocket_client(_host.substr(0, _host.find(':')), _host.substr(_host.find(':') + 1, _host.length()), "/?v=" + std::to_string(voice_protocol_version), OP_TEXT), + runner(nullptr), + connect_time(0), + mixer(std::make_unique()), + port(0), + ssrc(0), + timescale(1000000), + paused(false), + encoder(nullptr), + repacketizer(nullptr), + fd(INVALID_SOCKET), + sequence(0), + receive_sequence(-1), + timestamp(0), + packet_nonce(1), + last_timestamp(std::chrono::high_resolution_clock::now()), + sending(false), + tracks(0), + dave_version(enable_dave ? dave_version_1 : dave_version_none), + creator(_cluster), + terminating(false), + heartbeat_interval(0), + last_heartbeat(time(nullptr)), + token(_token), + sessionid(_session_id), + server_id(_server_id), + channel_id(_channel_id) +{ + if (!discord_voice_client::sodium_initialised) { + if (sodium_init() < 0) { + throw dpp::voice_exception(err_sodium, "discord_voice_client::discord_voice_client; sodium_init() failed"); + } + discord_voice_client::sodium_initialised = true; + } + int opusError = 0; + encoder = opus_encoder_create(opus_sample_rate_hz, opus_channel_count, OPUS_APPLICATION_VOIP, &opusError); + if (opusError) { + throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_encoder_create() failed"); + } + repacketizer = opus_repacketizer_create(); + if (!repacketizer) { + throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_repacketizer_create() failed"); + } + try { + this->connect(); + } + catch (...) { + cleanup(); + throw; + } +} + +} diff --git a/src/dpp/voice/enabled/courier_loop.cpp b/src/dpp/voice/enabled/courier_loop.cpp new file mode 100644 index 0000000000..6526c7f8ba --- /dev/null +++ b/src/dpp/voice/enabled/courier_loop.cpp @@ -0,0 +1,174 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include + +#include +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +void discord_voice_client::voice_courier_loop(discord_voice_client& client, courier_shared_state_t& shared_state) { + utility::set_thread_name(std::string("vcourier/") + std::to_string(client.server_id)); + while (true) { + std::this_thread::sleep_for(std::chrono::milliseconds{client.iteration_interval}); + + struct flush_data_t { + snowflake user_id; + rtp_seq_t min_seq; + std::priority_queue parked_payloads; + std::vector> pending_decoder_ctls; + std::shared_ptr decoder; + }; + std::vector flush_data; + + /* + * Transport the payloads onto this thread, and + * release the lock as soon as possible. + */ + { + std::unique_lock lk(shared_state.mtx); + + /* mitigates vector resizing while holding the mutex */ + flush_data.reserve(shared_state.parked_voice_payloads.size()); + + bool has_payload_to_deliver = false; + for (auto &[user_id, parking_lot]: shared_state.parked_voice_payloads) { + has_payload_to_deliver = has_payload_to_deliver || !parking_lot.parked_payloads.empty(); + flush_data.push_back(flush_data_t{user_id, + parking_lot.range.min_seq, + std::move(parking_lot.parked_payloads), + /* Quickly check if we already have a decoder and only take the pending ctls if so. */ + parking_lot.decoder ? std::move(parking_lot.pending_decoder_ctls) + : decltype(parking_lot.pending_decoder_ctls){}, + parking_lot.decoder}); + parking_lot.range.min_seq = parking_lot.range.max_seq + 1; + parking_lot.range.min_timestamp = parking_lot.range.max_timestamp + 1; + } + + if (!has_payload_to_deliver) { + if (shared_state.terminating) { + /* We have delivered all data to handlers. Terminate now. */ + break; + } + + shared_state.signal_iteration.wait(lk); + /* + * More data came or about to terminate, or just a spurious wake. + * We need to collect the payloads again to determine what to do next. + */ + continue; + } + } + + if (client.creator->on_voice_receive.empty() && client.creator->on_voice_receive_combined.empty()) { + /* + * We do this check late, to ensure this thread drains the data + * and prevents accumulating them even when there are no handlers. + */ + continue; + } + + /* This 32 bit PCM audio buffer is an upmixed version of the streams + * combined for all users. This is a wider width audio buffer so that + * there is no clipping when there are many loud audio sources at once. + */ + opus_int32 pcm_mix[23040] = {0}; + size_t park_count = 0; + int max_samples = 0; + int samples = 0; + + for (auto &d: flush_data) { + if (!d.decoder) { + continue; + } + for (const auto &decoder_ctl: d.pending_decoder_ctls) { + decoder_ctl(*d.decoder); + } + for (rtp_seq_t seq = d.min_seq; !d.parked_payloads.empty(); ++seq) { + opus_int16 pcm[23040]; + if (d.parked_payloads.top().seq != seq) { + /* + * Lost a packet with sequence number "seq", + * But Opus decoder might be able to guess something. + */ + if (int samples = opus_decode(d.decoder.get(), nullptr, 0, pcm, 5760, 0); + samples >= 0) { + /* + * Since this sample comes from a lost packet, + * we can only pretend there is an event, without any raw payload byte. + */ + voice_receive_t vr(nullptr, "", &client, d.user_id, reinterpret_cast(pcm), + samples * opus_channel_count * sizeof(opus_int16)); + + park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); + client.creator->on_voice_receive.call(vr); + } + } else { + voice_receive_t &vr = *d.parked_payloads.top().vr; + if (vr.audio_data.size() > 0x7FFFFFFF) { + throw dpp::length_exception(err_massive_audio, "audio_data > 2GB! This should never happen!"); + } + if (samples = opus_decode(d.decoder.get(), vr.audio_data.data(), + static_cast(vr.audio_data.size() & 0x7FFFFFFF), pcm, 5760, 0); + samples >= 0) { + vr.reassign(&client, d.user_id, reinterpret_cast(pcm), + samples * opus_channel_count * sizeof(opus_int16)); + client.end_gain = 1.0f / client.moving_average; + park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); + client.creator->on_voice_receive.call(vr); + } + + d.parked_payloads.pop(); + } + } + } + + /* If combined receive is bound, dispatch it */ + if (park_count) { + + /* Downsample the 32 bit samples back to 16 bit */ + opus_int16 pcm_downsample[23040] = {0}; + opus_int16 *pcm_downsample_ptr = pcm_downsample; + opus_int32 *pcm_mix_ptr = pcm_mix; + client.increment = (client.end_gain - client.current_gain) / static_cast(samples); + for (int64_t x = 0; x < (samples * opus_channel_count) / client.mixer->byte_blocks_per_register; ++x) { + client.mixer->collect_single_register(pcm_mix_ptr, pcm_downsample_ptr, client.current_gain, client.increment); + client.current_gain += client.increment * static_cast(client.mixer->byte_blocks_per_register); + pcm_mix_ptr += client.mixer->byte_blocks_per_register; + pcm_downsample_ptr += client.mixer->byte_blocks_per_register; + } + + voice_receive_t vr(nullptr, "", &client, 0, reinterpret_cast(pcm_downsample), + max_samples * opus_channel_count * sizeof(opus_int16)); + + client.creator->on_voice_receive_combined.call(vr); + } + } +} + +} diff --git a/src/dpp/voice/enabled/discover_ip.cpp b/src/dpp/voice/enabled/discover_ip.cpp new file mode 100644 index 0000000000..ea4f310308 --- /dev/null +++ b/src/dpp/voice/enabled/discover_ip.cpp @@ -0,0 +1,206 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include "enabled.h" + +#ifdef _WIN32 + #include + #include + #include + #define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout) + #define pollfd WSAPOLLFD +#else + #include + #include + #include +#endif + +namespace dpp { + +/** + * https://discord.com/developers/docs/topics/voice-connections#ip-discovery + */ + +/** + * @brief Represents an IP discovery packet sent to Discord or received + * from Discord. + */ +struct ip_discovery_packet { + + /** + * @brief Maximum size of packet + */ + static constexpr int DISCOVERY_PACKET_SIZE = 74; + + /** + * @brief Maximum length of IP address string + */ + static constexpr int ADDRESS_BUFFER_SIZE = 64; + + /** + * @brief Type of packet + */ + uint16_t type; + + /** + * @brief Length of packet + */ + uint16_t length; + + /** + * @brief SSRC of sender + */ + uint32_t ssrc; + + /** + * @brief Address buffer, contains IP address in returned packet + */ + char address[ADDRESS_BUFFER_SIZE]{0}; // NOLINT + + /** + * @brief Port number, contains port in returned packet + */ + uint16_t port; + + /** + * @brief Construct discovery packet from inbound recv() buffer contents + * @param packet_buffer recv buffer contents of at least ADDRESS_BUFFER_SIZE bytes + */ + ip_discovery_packet(char* packet_buffer) + : type(ntohs(packet_buffer[0] << 8 | packet_buffer[1])), + length(ntohs(packet_buffer[2] << 8 | packet_buffer[3])), + ssrc(ntohl(packet_buffer[4] << 24 | packet_buffer[5] << 16 | packet_buffer[6] << 8 | packet_buffer[7])), + port(ntohs(packet_buffer[72] << 8 | packet_buffer[73])) + { + std::memcpy(address, packet_buffer + 8, ADDRESS_BUFFER_SIZE); + } + + /** + * @brief Build a const char* buffer for sending with send() to make a request + * @return char buffer + */ + const std::array build_buffer() { + std::array buffer{0}; + buffer[0] = ((type & 0xff00) >> 8) & 0xff; + buffer[1] = type & 0xff; + buffer[2] = (length & 0xff00) >> 8; + buffer[3] = length & 0xff; + buffer[4] = ((ssrc & 0xff000000) >> 24) & 0xff; + buffer[5] = ((ssrc & 0x00ff0000) >> 16) & 0xff; + buffer[6] = ((ssrc & 0x0000ff00) >> 8) & 0xff; + buffer[7] = ssrc & 0x000000ff; + return buffer; + } + + /** + * @brief Deleted default constructor + */ + ip_discovery_packet() = delete; + + /** + * @brief Build a request packet for a given SSRC. + * type and length will be initialised correctly and the address + * buffer will be zeroed. + * @param _ssrc SSRC value + */ + ip_discovery_packet(uint32_t _ssrc) : + /* Packet length is size of header minus type and length fields, usually 70 bytes */ + type(0x01), length(DISCOVERY_PACKET_SIZE - sizeof(type) - sizeof(length)), + ssrc(_ssrc), port(0) { + std::memset(&address, 0, ADDRESS_BUFFER_SIZE); + } +}; + +/** + * @brief Allocates a dpp::socket, closing it on destruction + */ +struct raii_socket { + dpp::socket fd; + + raii_socket() : fd(::socket(AF_INET, SOCK_DGRAM, 0)) { }; + raii_socket(raii_socket&) = delete; + raii_socket(raii_socket&&) = delete; + raii_socket operator=(raii_socket&) = delete; + raii_socket operator=(raii_socket&&) = delete; + ~raii_socket() { close_socket(fd); }; +}; + +constexpr int discovery_timeout = 1000; + +std::string discord_voice_client::discover_ip() { + + if (!external_ip.empty()) { + return external_ip; + } + + raii_socket socket; + ip_discovery_packet discovery(this->ssrc); + + if (socket.fd >= 0) { + sockaddr_in servaddr{}; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(0); + if (bind(socket.fd, reinterpret_cast(&servaddr), sizeof(servaddr)) < 0) { + log(ll_warning, "Could not bind socket for IP discovery"); + return ""; + } + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(this->port); + servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); + if (::connect(socket.fd, reinterpret_cast(&servaddr), sizeof(sockaddr_in)) < 0) { + log(ll_warning, "Could not connect socket for IP discovery"); + return ""; + } + if (::send(socket.fd, discovery.build_buffer().data(), ip_discovery_packet::DISCOVERY_PACKET_SIZE, 0) == -1) { + log(ll_warning, "Could not send packet for IP discovery"); + return ""; + } + /* Wait one second for receipt of IP detection packet response */ + pollfd pfd{}; + pfd.fd = socket.fd; + pfd.events = POLLIN; + int ret = ::poll(&pfd, 1, discovery_timeout); + switch (ret) { + case -1: + log(ll_warning, "poll() error on IP discovery"); + return ""; + case 0: + log(ll_warning, "Timed out in IP discovery"); + return ""; + default: + char buffer[ip_discovery_packet::DISCOVERY_PACKET_SIZE]{0}; + if (recv(socket.fd, buffer, sizeof(buffer), 0) == -1) { + log(ll_warning, "Could not receive packet for IP discovery"); + return ""; + } + ip_discovery_packet inbound_packet(buffer); + return {inbound_packet.address}; + } + } + return {}; +} + +} diff --git a/src/dpp/voice/enabled/displayable_code.cpp b/src/dpp/voice/enabled/displayable_code.cpp new file mode 100644 index 0000000000..364ace13d4 --- /dev/null +++ b/src/dpp/voice/enabled/displayable_code.cpp @@ -0,0 +1,51 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include + +#include "../../dave/encryptor.h" + +namespace dpp { + +std::string generate_displayable_code(const std::vector &data, size_t desired_length = 30, size_t group_size = 5) { + + const size_t group_modulus = std::pow(10, group_size); + std::stringstream result; + + for (size_t i = 0; i < desired_length; i += group_size) { + size_t group_value{0}; + + for (size_t j = group_size; j > 0; --j) { + const size_t next_byte = data.at(i + (group_size - j)); + group_value = (group_value << 8) | next_byte; + } + group_value %= group_modulus; + result << std::setw(group_size) << std::setfill('0') << std::to_string(group_value) << " "; + } + + return result.str(); +} + +} diff --git a/src/dpp/voice/enabled/enabled.h b/src/dpp/voice/enabled/enabled.h new file mode 100644 index 0000000000..78b55958d5 --- /dev/null +++ b/src/dpp/voice/enabled/enabled.h @@ -0,0 +1,110 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../dave/session.h" +#include "../../dave/decryptor.h" +#include "../../dave/encryptor.h" + +#ifdef _WIN32 +#include + #include + #include +#else + #include + #include + #include +#endif + +namespace dpp { + +struct dave_state { + std::unique_ptr dave_session{}; + std::shared_ptr<::mlspp::SignaturePrivateKey> mls_key; + std::vector cached_commit; + uint64_t transition_id{0}; + struct { + uint64_t id{0}; + uint64_t protocol_version{0}; + bool is_pending{false}; + } pending_transition; + std::map> decryptors; + std::unique_ptr encryptor; + std::string privacy_code; +}; + +/** + * @brief Represents an RTP packet. Size should always be exactly 12. + */ +struct rtp_header { + uint16_t constant; + uint16_t sequence; + uint32_t timestamp; + uint32_t ssrc; + + rtp_header(uint16_t _seq, uint32_t _ts, uint32_t _ssrc) : constant(htons(0x8078)), sequence(htons(_seq)), timestamp(htonl(_ts)), ssrc(htonl(_ssrc)) { + } +}; + +/** +* @brief Transport encryption type (libsodium) +*/ +constexpr std::string_view transport_encryption_protocol = "aead_xchacha20_poly1305_rtpsize"; + +std::string generate_displayable_code(const std::vector &data, size_t desired_length = 30, size_t group_size = 5); + +size_t audio_mix(discord_voice_client &client, audio_mixer &mixer, opus_int32 *pcm_mix, const opus_int16 *pcm, size_t park_count, int samples, int &max_samples); + +} diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp new file mode 100644 index 0000000000..5ade5ac4f0 --- /dev/null +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -0,0 +1,451 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcode) { + json j; + + /** + * MLS frames come in as type OP_BINARY, we can also reply to them as type OP_BINARY. + */ + if (opcode == OP_BINARY && data.size() >= sizeof(dave_binary_header_t)) { + + dave_binary_header_t dave_header(data); + + switch (dave_header.opcode) { + case voice_client_dave_mls_external_sender: { + log(ll_debug, "voice_client_dave_mls_external_sender"); + + mls_state->dave_session->set_external_sender(dave_header.get_data()); + + mls_state->encryptor = std::make_unique(*creator); + mls_state->decryptors.clear(); + } + break; + case voice_client_dave_mls_proposals: { + log(ll_debug, "voice_client_dave_mls_proposals"); + + std::optional> response = mls_state->dave_session->process_proposals(dave_header.get_data(), dave_mls_user_list); + if (response.has_value()) { + auto r = response.value(); + mls_state->cached_commit = r; + r.insert(r.begin(), voice_client_dave_mls_commit_message); + this->write(std::string_view(reinterpret_cast(r.data()), r.size()), OP_BINARY); + } + } + break; + case voice_client_dave_announce_commit_transaction: { + log(ll_debug, "voice_client_dave_announce_commit_transaction"); + auto r = mls_state->dave_session->process_commit(mls_state->cached_commit); + for (const auto& user : dave_mls_user_list) { + log(ll_debug, "Setting decryptor key ratchet for user: " + user + ", protocol version: " + std::to_string(mls_state->dave_session->get_protocol_version())); + dpp::snowflake u{user}; + mls_state->decryptors.emplace(u, std::make_unique(*creator)); + mls_state->decryptors.find(u)->second->transition_to_key_ratchet(mls_state->dave_session->get_key_ratchet(user)); + } + mls_state->encryptor->set_key_ratchet(mls_state->dave_session->get_key_ratchet(creator->me.id.str())); + + /** + * https://www.ietf.org/archive/id/draft-ietf-mls-protocol-14.html#name-epoch-authenticators + * 9.7. Epoch Authenticators + * The main MLS key schedule provides a per-epoch epoch_authenticator. If one member of the group is being impersonated by an active attacker, + * the epoch_authenticator computed by their client will differ from those computed by the other group members. + */ + mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->get_last_epoch_authenticator()); + log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); + + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } + } + break; + case voice_client_dave_mls_welcome: { + this->mls_state->transition_id = dave_header.get_transition_id(); + log(ll_debug, "voice_client_dave_mls_welcome with transition id " + std::to_string(this->mls_state->transition_id)); + auto r = mls_state->dave_session->process_welcome(dave_header.get_data(), dave_mls_user_list); + if (r.has_value()) { + for (const auto& user : dave_mls_user_list) { + log(ll_debug, "Setting decryptor key ratchet for user: " + user + ", protocol version: " + std::to_string(mls_state->dave_session->get_protocol_version())); + dpp::snowflake u{user}; + mls_state->decryptors.emplace(u, std::make_unique(*creator)); + mls_state->decryptors.find(u)->second->transition_to_key_ratchet(mls_state->dave_session->get_key_ratchet(user)); + } + mls_state->encryptor->set_key_ratchet(mls_state->dave_session->get_key_ratchet(creator->me.id.str())); + } + mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->get_last_epoch_authenticator()); + log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); + + json obj = { + { "op", voice_client_dave_transition_ready }, + { + "d", + { + { "transition_id", this->mls_state->transition_id }, + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } + break; + default: + log(ll_debug, "Unexpected DAVE frame opcode"); + log(dpp::ll_trace, "R: " + dpp::utility::debug_dump(reinterpret_cast(data.data()), data.length())); + break; + } + + return true; + } + + try { + log(dpp::ll_trace, std::string("R: ") + data); + j = json::parse(data); + } + catch (const std::exception &e) { + log(dpp::ll_error, std::string("discord_voice_client::handle_frame ") + e.what() + ": " + data); + return true; + } + + if (j.find("seq") != j.end() && j["seq"].is_number()) { + /** + * Save the sequence number needed for heartbeat and resume payload. + * + * NOTE: Contrary to the documentation, discord does not seem to send messages with sequence number + * in order, should we only save the sequence if it's larger number? + */ + receive_sequence = j["seq"].get(); + } + + if (j.find("op") != j.end()) { + uint32_t op = j["op"]; + + switch (op) { + /* Ping acknowledgement */ + case voice_opcode_connection_heartbeat_ack: + /* These opcodes do not require a response or further action */ + break; + case voice_opcode_media_sink: + case voice_client_flags: { + } + break; + case voice_client_platform: { + voice_client_platform_t vcp(nullptr, data); + vcp.voice_client = this; + vcp.user_id = snowflake_not_null(&j["d"], "user_id"); + vcp.platform = static_cast(int8_not_null(&j["d"], "platform")); + creator->on_voice_client_platform.call(vcp); + } + break; + case voice_opcode_multiple_clients_connect: { + dave_mls_user_list = j["d"]["user_ids"]; + log(ll_debug, "Number of clients in voice channel: " + std::to_string(dave_mls_user_list.size())); + } + break; + case voice_client_dave_mls_invalid_commit_welcome: { + this->mls_state->transition_id = j["d"]["transition_id"]; + log(ll_debug, "voice_client_dave_mls_invalid_commit_welcome transition id " + std::to_string(this->mls_state->transition_id)); + } + break; + case voice_client_dave_execute_transition: { + log(ll_debug, "voice_client_dave_execute_transition"); + this->mls_state->transition_id = j["d"]["transition_id"]; + + if (this->mls_state->pending_transition.is_pending) { + if (this->mls_state->transition_id != this->mls_state->pending_transition.id) { + log(ll_debug, "voice_client_dave_execute_transition unexpected transition_id, we never received voice_client_dave_prepare_transition event with this id: " + std::to_string(this->mls_state->pending_transition.id)); + } else { + dave_version = this->mls_state->pending_transition.protocol_version == 1 ? dave_version_1 : dave_version_none; + + if (this->mls_state->pending_transition.protocol_version != 0 && dave_version == dave_version_none) { + log(ll_debug, "voice_client_dave_execute_transition unexpected protocol version: " + std::to_string(this->mls_state->pending_transition.protocol_version)+ " in transition " + std::to_string(this->mls_state->pending_transition.id)); + } + + this->mls_state->privacy_code.clear(); + this->dave_mls_user_list.clear(); + + this->mls_state->pending_transition.is_pending = false; + } + } + } + break; + /* "The protocol only uses this opcode to indicate when a downgrade to protocol version 0 is upcoming." */ + case voice_client_dave_prepare_transition: { + uint64_t transition_id = j["d"]["transition_id"]; + uint64_t protocol_version = j["d"]["protocol_version"]; + this->mls_state->pending_transition = {transition_id, protocol_version, true}; + log(ll_debug, "voice_client_dave_prepare_transition version=" + std::to_string(protocol_version) + " for transition " + std::to_string(transition_id)); + + json obj = { + { "op", voice_client_dave_transition_ready }, + { + "d", + { + { "transition_id", this->mls_state->transition_id }, + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } + break; + case voice_client_dave_prepare_epoch: { + uint64_t protocol_version = j["d"]["protocol_version"]; + uint64_t epoch = j["d"]["epoch"]; + log(ll_debug, "voice_client_dave_prepare_epoch version=" + std::to_string(protocol_version) + " for epoch " + std::to_string(epoch)); + if (epoch == 1) { + mls_state->dave_session->reset(); + mls_state->dave_session->init(dave::max_protocol_version(), channel_id, creator->me.id.str(), mls_state->mls_key); + auto key_response = mls_state->dave_session->get_marshalled_key_package(); + key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); + this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); + } + } + break; + /* Client Disconnect */ + case voice_opcode_client_disconnect: { + if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null()) { + snowflake u_id = snowflake_not_null(&j["d"], "user_id"); + auto it = std::find_if(ssrc_map.begin(), ssrc_map.end(), + [&u_id](const auto & p) { return p.second == u_id; }); + + if (it != ssrc_map.end()) { + ssrc_map.erase(it); + } + + auto it_dave = dave_mls_user_list.find(j["d"]["user_id"]); + if (it_dave != dave_mls_user_list.end()) { + dave_mls_user_list.erase(it_dave); + } + + if (!creator->on_voice_client_disconnect.empty()) { + voice_client_disconnect_t vcd(nullptr, data); + vcd.voice_client = this; + vcd.user_id = u_id; + creator->on_voice_client_disconnect.call(vcd); + } + } + } + break; + /* Speaking */ + case voice_opcode_client_speaking: + /* Client Connect (doesn't seem to work) */ + case voice_opcode_client_connect: { + if (j.find("d") != j.end() + && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null() + && j["d"].find("ssrc") != j["d"].end() && !j["d"]["ssrc"].is_null() && j["d"]["ssrc"].is_number_integer()) { + uint32_t u_ssrc = j["d"]["ssrc"].get(); + snowflake u_id = snowflake_not_null(&j["d"], "user_id"); + ssrc_map[u_ssrc] = u_id; + + if (!creator->on_voice_client_speaking.empty()) { + voice_client_speaking_t vcs(nullptr, data); + vcs.voice_client = this; + vcs.user_id = u_id; + vcs.ssrc = u_ssrc; + creator->on_voice_client_speaking.call(vcs); + } + } + } + break; + /* Voice resume */ + case voice_opcode_connection_resumed: + log(ll_debug, "Voice connection resumed"); + break; + /* Voice HELLO */ + case voice_opcode_connection_hello: { + if (j.find("d") != j.end() && j["d"].find("heartbeat_interval") != j["d"].end() && !j["d"]["heartbeat_interval"].is_null()) { + this->heartbeat_interval = j["d"]["heartbeat_interval"].get(); + } + + /* Reset receive_sequence on HELLO */ + receive_sequence = -1; + + if (!modes.empty()) { + log(dpp::ll_debug, "Resuming voice session " + this->sessionid + "..."); + json obj = { + { "op", voice_opcode_connection_resume }, + { + "d", + { + { "server_id", std::to_string(this->server_id) }, + { "session_id", this->sessionid }, + { "token", this->token }, + { "seq_ack", this->receive_sequence }, + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } else { + log(dpp::ll_debug, "Connecting new voice session (DAVE: " + std::string(dave_version == dave_version_1 ? "Enabled" : "Disabled") + ")..."); + json obj = { + { "op", voice_opcode_connection_identify }, + { + "d", + { + { "user_id", creator->me.id }, + { "server_id", std::to_string(this->server_id) }, + { "session_id", this->sessionid }, + { "token", this->token }, + { "max_dave_protocol_version", dave_version }, + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } + this->connect_time = time(nullptr); + } + break; + /* Session description */ + case voice_opcode_connection_description: { + json &d = j["d"]; + size_t ofs = 0; + for (auto & c : d["secret_key"]) { + secret_key[ofs++] = (uint8_t)c; + if (ofs > secret_key.size() - 1) { + break; + } + } + has_secret_key = true; + + /* Reset packet_nonce */ + packet_nonce = 1; + + bool ready_now = false; + + if (dave_version != dave_version_none) { + if (j["d"]["dave_protocol_version"] != static_cast(dave_version)) { + log(ll_error, "We requested DAVE E2EE but didn't receive it from the server, downgrading..."); + dave_version = dave_version_none; + ready_now = true; + } + + if (mls_state == nullptr) { + mls_state = std::make_unique(); + } + if (mls_state->dave_session == nullptr) { + mls_state->dave_session = std::make_unique( + *creator, + nullptr, "", [this](std::string const& s1, std::string const& s2) { + log(ll_debug, "Dave session constructor callback: " + s1 + ", " + s2); + }); + mls_state->dave_session->init(dave::max_protocol_version(), channel_id, creator->me.id.str(), mls_state->mls_key); + } + auto key_response = mls_state->dave_session->get_marshalled_key_package(); + key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); + this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); + } + + if (ready_now) { + /* This is needed to start voice receiving and make sure that the start of sending isn't cut off */ + send_silence(20); + /* Fire on_voice_ready */ + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } + } + } + break; + /* Voice ready */ + case voice_opcode_connection_ready: { + /* Video stream stuff comes in this frame too, but we can't use it (YET!) */ + json &d = j["d"]; + this->ip = d["ip"].get(); + this->port = d["port"].get(); + this->ssrc = d["ssrc"].get(); + // Modes + for (auto & m : d["modes"]) { + this->modes.push_back(m.get()); + } + log(ll_debug, "Voice websocket established; UDP endpoint: " + ip + ":" + std::to_string(port) + " [ssrc=" + std::to_string(ssrc) + "] with " + std::to_string(modes.size()) + " modes"); + + dpp::socket newfd = 0; + if ((newfd = ::socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + + sockaddr_in servaddr{}; + memset(&servaddr, 0, sizeof(sockaddr_in)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(0); + + if (bind(newfd, reinterpret_cast(&servaddr), sizeof(servaddr)) < 0) { + throw dpp::connection_exception(err_bind_failure, "Can't bind() client UDP socket"); + } + + if (!set_nonblocking(newfd, true)) { + throw dpp::connection_exception(err_nonblocking_failure, "Can't switch voice UDP socket to non-blocking mode!"); + } + + /* Hook poll() in the ssl_client to add a new file descriptor */ + this->fd = newfd; + this->custom_writeable_fd = [this] { return want_write(); }; + this->custom_readable_fd = [this] { return want_read(); }; + this->custom_writeable_ready = [this] { write_ready(); }; + this->custom_readable_ready = [this] { read_ready(); }; + + int bound_port = 0; + sockaddr_in sin{}; + socklen_t len = sizeof(sin); + if (getsockname(this->fd, reinterpret_cast(&sin), &len) > -1) { + bound_port = ntohs(sin.sin_port); + } + + this->write(json({ + { "op", voice_opcode_connection_select_protocol }, + { "d", { + { "protocol", "udp" }, + { "data", { + { "address", discover_ip() }, + { "port", bound_port }, + { "mode", transport_encryption_protocol } + } + } + } + } + }).dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } + } + break; + default: { + log(ll_debug, "Unknown voice opcode " + std::to_string(op) + ": " + data); + } + break; + } + } + return true; +} + + +} diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp new file mode 100644 index 0000000000..066cacdb53 --- /dev/null +++ b/src/dpp/voice/enabled/opus.cpp @@ -0,0 +1,206 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include + +#include +#include "../../dave/array_view.h" +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, const size_t length) { + if (length < 4) { + throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size can't be less than 4"); + } + + if ((length % 4) != 0) { + throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size should be divisible by 4"); + } + + if (length > send_audio_raw_max_length) { + std::string s_audio_data(reinterpret_cast(audio_data), length); + + while (s_audio_data.length() > send_audio_raw_max_length) { + std::string packet(s_audio_data.substr(0, send_audio_raw_max_length)); + const auto packet_size = static_cast(packet.size()); + + s_audio_data.erase(s_audio_data.begin(), s_audio_data.begin() + packet_size); + + send_audio_raw(reinterpret_cast(packet.data()), packet_size); + } + + return *this; + } + + if (length < send_audio_raw_max_length) { + std::string packet(reinterpret_cast(audio_data), length); + packet.resize(send_audio_raw_max_length, 0); + + return send_audio_raw(reinterpret_cast(packet.data()), packet.size()); + } + + opus_int32 encoded_audio_max_length = (opus_int32)length; + std::vector encoded_audio(encoded_audio_max_length); + size_t encoded_audio_length = encoded_audio_max_length; + encoded_audio_length = this->encode(reinterpret_cast(audio_data), length, encoded_audio.data(), encoded_audio_length); + send_audio_opus(encoded_audio.data(), encoded_audio_length); + return *this; +} + +discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length) { + int samples = opus_packet_get_nb_samples(opus_packet, (opus_int32)length, opus_sample_rate_hz); + uint64_t duration = (samples / 48) / (timescale / 1000000); + send_audio_opus(opus_packet, length, duration); + return *this; +} + +discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { + int frame_size = (int)(48 * duration * (timescale / 1000000)); + opus_int32 encoded_audio_max_length = (opus_int32)length; + std::vector encoded_audio(encoded_audio_max_length); + size_t encoded_audio_length = encoded_audio_max_length; + + encoded_audio_length = length; + encoded_audio.reserve(length); + memcpy(encoded_audio.data(), opus_packet, length); + + if (this->is_end_to_end_encrypted()) { + + std::vector encrypted_buffer(this->mls_state->encryptor->get_max_ciphertext_byte_size(dave::media_type::media_audio, length)); + size_t out_size{0}; + + auto result = this->mls_state->encryptor->encrypt( + dave::media_type::media_audio, + ssrc, + dave::make_array_view(encoded_audio.data(), length), + dave::make_array_view(encrypted_buffer), + &out_size + ); + encrypted_buffer.resize(out_size); + if (result != dave::encryptor::result_code::rc_success) { + log(ll_warning, "DAVE Encryption failure: " + std::to_string(result)); + } else { + encoded_audio = encrypted_buffer; + encoded_audio_length = encoded_audio.size(); + } + + } + + ++sequence; + rtp_header header(sequence, timestamp, (uint32_t)ssrc); + + /* Expected payload size is unencrypted header + encrypted opus packet + unencrypted 32 bit nonce */ + size_t packet_siz = sizeof(header) + (encoded_audio_length + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + + std::vector payload(packet_siz); + + /* Set RTP header */ + std::memcpy(payload.data(), &header, sizeof(header)); + + /* Convert nonce to big-endian */ + uint32_t noncel = htonl(packet_nonce); + + /* 24 byte is needed for encrypting, discord just want 4 byte so just fill up the rest with null */ + unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { '\0' }; + memcpy(encrypt_nonce, &noncel, sizeof(noncel)); + + /* Execute */ + crypto_aead_xchacha20poly1305_ietf_encrypt( + payload.data() + sizeof(header), + nullptr, + encoded_audio.data(), + encoded_audio_length, + /* The RTP Header as Additional Data */ + reinterpret_cast(&header), + sizeof(header), + nullptr, + static_cast(encrypt_nonce), + secret_key.data() + ); + + /* Append the 4 byte nonce to the resulting payload */ + std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); + + this->send(reinterpret_cast(payload.data()), payload.size(), duration); + + timestamp += frame_size; + + /* Increment for next packet */ + packet_nonce++; + + speak(); + return *this; +} + +size_t discord_voice_client::encode(uint8_t *input, size_t inDataSize, uint8_t *output, size_t &outDataSize) { + outDataSize = 0; + int mEncFrameBytes = 11520; + int mEncFrameSize = 2880; + if (0 == (inDataSize % mEncFrameBytes)) { + bool isOk = true; + uint8_t *out = encode_buffer; + + memset(out, 0, sizeof(encode_buffer)); + repacketizer = opus_repacketizer_init(repacketizer); + if (!repacketizer) { + log(ll_warning, "opus_repacketizer_init(): failure"); + return outDataSize; + } + for (size_t i = 0; i < (inDataSize / mEncFrameBytes); ++ i) { + const opus_int16* pcm = reinterpret_cast(input + i * mEncFrameBytes); + int ret = opus_encode(encoder, pcm, mEncFrameSize, out, 65536); + if (ret > 0) { + int retval = opus_repacketizer_cat(repacketizer, out, ret); + if (retval != OPUS_OK) { + isOk = false; + log(ll_warning, "opus_repacketizer_cat(): " + std::string(opus_strerror(retval))); + break; + } + out += ret; + } else { + isOk = false; + log(ll_warning, "opus_encode(): " + std::string(opus_strerror(ret))); + break; + } + } + if (isOk) { + int ret = opus_repacketizer_out(repacketizer, output, 65536); + if (ret > 0) { + outDataSize = ret; + } else { + log(ll_warning, "opus_repacketizer_out(): " + std::string(opus_strerror(ret))); + } + } + } else { + throw dpp::voice_exception(err_invalid_voice_packet_length, "Invalid input data length: " + std::to_string(inDataSize) + ", must be n times of " + std::to_string(mEncFrameBytes)); + } + return outDataSize; +} + + +} diff --git a/src/dpp/voice/enabled/read_ready.cpp b/src/dpp/voice/enabled/read_ready.cpp new file mode 100644 index 0000000000..51a817fbed --- /dev/null +++ b/src/dpp/voice/enabled/read_ready.cpp @@ -0,0 +1,215 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include + +#include +#include "../../dave/decryptor.h" + +#include "enabled.h" + +namespace dpp { + +void discord_voice_client::read_ready() +{ + uint8_t buffer[65535]; + int packet_size = this->udp_recv(reinterpret_cast(buffer), sizeof(buffer)); + + bool receive_handler_is_empty = creator->on_voice_receive.empty() && creator->on_voice_receive_combined.empty(); + if (packet_size <= 0 || receive_handler_is_empty) { + /* Nothing to do */ + return; + } + + constexpr size_t header_size = 12; + if (static_cast(packet_size) < header_size) { + /* Invalid RTP payload */ + return; + } + + /* It's a "silence packet" - throw it away. */ + if (packet_size < 44) { + return; + } + + if (uint8_t payload_type = buffer[1] & 0b0111'1111; + 72 <= payload_type && payload_type <= 76) { + /* + * This is an RTCP payload. Discord is known to send + * RTCP Receiver Reports. + * + * See https://datatracker.ietf.org/doc/html/rfc3551#section-6 + */ + return; + } + + voice_payload vp{0, // seq, populate later + 0, // timestamp, populate later + std::make_unique(nullptr, std::string(reinterpret_cast(buffer), packet_size))}; + + vp.vr->voice_client = this; + + uint32_t speaker_ssrc; + { /* Get the User ID of the speaker */ + std::memcpy(&speaker_ssrc, &buffer[8], sizeof(uint32_t)); + speaker_ssrc = ntohl(speaker_ssrc); + vp.vr->user_id = ssrc_map[speaker_ssrc]; + } + + /* Get the sequence number of the voice UDP packet */ + std::memcpy(&vp.seq, &buffer[2], sizeof(rtp_seq_t)); + vp.seq = ntohs(vp.seq); + + /* Get the timestamp of the voice UDP packet */ + std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); + vp.timestamp = ntohl(vp.timestamp); + + constexpr size_t nonce_size = sizeof(uint32_t); + /* Nonce is 4 byte at the end of payload with zero padding */ + uint8_t nonce[24] = { 0 }; + std::memcpy(nonce, buffer + packet_size - nonce_size, nonce_size); + + /* Get the number of CSRC in header */ + const size_t csrc_count = buffer[0] & 0b0000'1111; + /* Skip to the encrypted voice data */ + const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; + size_t total_header_len = offset_to_data; + + uint8_t* ciphertext = buffer + offset_to_data; + size_t ciphertext_len = packet_size - offset_to_data - nonce_size; + + size_t ext_len = 0; + if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { + /** + * Get the RTP Extensions size, we only get the size here because + * the extension itself is encrypted along with the opus packet + */ + { + uint16_t ext_len_in_words; + memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); + ext_len_in_words = ntohs(ext_len_in_words); + ext_len = sizeof(uint32_t) * ext_len_in_words; + } + constexpr size_t ext_header_len = sizeof(uint16_t) * 2; + ciphertext += ext_header_len; + ciphertext_len -= ext_header_len; + total_header_len += ext_header_len; + } + + uint8_t decrypted[65535] = { 0 }; + unsigned long long opus_packet_len = 0; + if (crypto_aead_xchacha20poly1305_ietf_decrypt( + decrypted, &opus_packet_len, + nullptr, + ciphertext, ciphertext_len, + buffer, + /** + * Additional Data: + * The whole header (including csrc list) + + * 4 byte extension header (magic 0xBEDE + 16-bit denoting extension length) + */ + total_header_len, + nonce, secret_key.data()) != 0) { + /* Invalid Discord RTP payload. */ + return; + } + + uint8_t *opus_packet = decrypted; + if (ext_len > 0) { + /* Skip previously encrypted RTP Header Extension */ + opus_packet += ext_len; + opus_packet_len -= ext_len; + } + + /** + * If DAVE is enabled, use the user's ratchet to decrypt the OPUS audio data + */ + std::vector frame; + if (is_end_to_end_encrypted()) { + auto decryptor = mls_state->decryptors.find(vp.vr->user_id); + if (decryptor != mls_state->decryptors.end()) { + frame.resize(decryptor->second->get_max_plaintext_byte_size(dave::media_type::media_audio, opus_packet_len)); + size_t enc_len = decryptor->second->decrypt( + dave::media_type::media_audio, + dave::make_array_view(opus_packet, opus_packet_len), + dave::make_array_view(frame) + ); + if (enc_len > 0) { + opus_packet = frame.data(); + opus_packet_len = enc_len; + } + } + } + + /* + * We're left with the decrypted, opus-encoded data. + * Park the payload and decode on the voice courier thread. + */ + vp.vr->audio_data.assign(opus_packet, opus_packet + opus_packet_len); + + { + std::lock_guard lk(voice_courier_shared_state.mtx); + auto& [range, payload_queue, pending_decoder_ctls, decoder] = voice_courier_shared_state.parked_voice_payloads[vp.vr->user_id]; + + if (!decoder) { + /* + * Most likely this is the first time we encounter this speaker. + * Do some initialization for not only the decoder but also the range. + */ + range.min_seq = vp.seq; + range.min_timestamp = vp.timestamp; + + int opus_error = 0; + decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), + &opus_decoder_destroy); + if (opus_error) { + /** + * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, + * which would otherwise conflict as every C library loves to use values from -1 downwards. + */ + throw dpp::voice_exception((exception_error_code)(opus_error - 10), "discord_voice_client::discord_voice_client; opus_decoder_create() failed"); + } + } + + if (vp.seq < range.min_seq && vp.timestamp < range.min_timestamp) { + /* This packet arrived too late. We can only discard it. */ + return; + } + range.max_seq = vp.seq; + range.max_timestamp = vp.timestamp; + payload_queue.push(std::move(vp)); + } + + voice_courier_shared_state.signal_iteration.notify_one(); + + if (!voice_courier.joinable()) { + /* Courier thread is not running, start it */ + voice_courier = std::thread(&voice_courier_loop, + std::ref(*this), + std::ref(voice_courier_shared_state)); + } +} + +} diff --git a/src/dpp/voice/enabled/read_write.cpp b/src/dpp/voice/enabled/read_write.cpp new file mode 100644 index 0000000000..1702e6cf13 --- /dev/null +++ b/src/dpp/voice/enabled/read_write.cpp @@ -0,0 +1,74 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include "../../dave/encryptor.h" +#include "enabled.h" + +namespace dpp { + +dpp::socket discord_voice_client::want_write() { + std::lock_guard lock(this->stream_mutex); + if (!this->paused && !outbuf.empty()) { + return fd; + } + return INVALID_SOCKET; + +} + +dpp::socket discord_voice_client::want_read() { + return fd; +} + + +void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { + std::lock_guard lock(this->stream_mutex); + voice_out_packet frame; + frame.packet = std::string(packet, len); + frame.duration = duration; + outbuf.emplace_back(frame); +} + +int discord_voice_client::udp_send(const char* data, size_t length) { + sockaddr_in servaddr{}; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(this->port); + servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); + return static_cast(sendto( + this->fd, + data, + static_cast(length), + 0, + reinterpret_cast(&servaddr), + static_cast(sizeof(sockaddr_in)) + )); +} + +int discord_voice_client::udp_recv(char* data, size_t max_length) +{ + return static_cast(recv(this->fd, data, static_cast(max_length), 0)); +} + +} \ No newline at end of file diff --git a/src/dpp/voice/enabled/thread.cpp b/src/dpp/voice/enabled/thread.cpp new file mode 100644 index 0000000000..0082eb0a72 --- /dev/null +++ b/src/dpp/voice/enabled/thread.cpp @@ -0,0 +1,87 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include "../../dave/encryptor.h" +#include "enabled.h" + +namespace dpp { + +void discord_voice_client::thread_run() +{ + utility::set_thread_name(std::string("vc/") + std::to_string(server_id)); + + size_t times_looped = 0; + time_t last_loop_time = time(nullptr); + + do { + bool error = false; + ssl_client::read_loop(); + ssl_client::close(); + + time_t current_time = time(nullptr); + /* Here, we check if it's been longer than 3 seconds since the previous loop, + * this gives us time to see if it's an actual disconnect, or an error. + * This will prevent us from looping too much, meaning error codes do not cause an infinite loop. + */ + if (current_time - last_loop_time >= 3) + times_looped = 0; + + /* This does mean we'll always have times_looped at a minimum of 1, this is intended. */ + times_looped++; + /* If we've looped 5 or more times, abort the loop. */ + if (times_looped >= 5) { + log(dpp::ll_warning, "Reached max loops whilst attempting to read from the websocket. Aborting websocket."); + break; + } + + last_loop_time = current_time; + + if (!terminating) { + log(dpp::ll_debug, "Attempting to reconnect the websocket..."); + do { + try { + ssl_client::connect(); + websocket_client::connect(); + } + catch (const std::exception &e) { + log(dpp::ll_error, std::string("Error establishing voice websocket connection, retry in 5 seconds: ") + e.what()); + ssl_client::close(); + std::this_thread::sleep_for(std::chrono::seconds(5)); + error = true; + } + } while (error && !terminating); + } + } while(!terminating); +} + +void discord_voice_client::run() +{ + this->runner = new std::thread(&discord_voice_client::thread_run, this); + this->thread_id = runner->native_handle(); +} + + +} diff --git a/src/dpp/voice/enabled/voice_payload.cpp b/src/dpp/voice/enabled/voice_payload.cpp new file mode 100644 index 0000000000..afc871a3d7 --- /dev/null +++ b/src/dpp/voice/enabled/voice_payload.cpp @@ -0,0 +1,69 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include +#include + +namespace dpp { + +bool discord_voice_client::voice_payload::operator<(const voice_payload& other) const { + if (timestamp != other.timestamp) { + return timestamp > other.timestamp; + } + + constexpr rtp_seq_t wrap_around_test_boundary = 5000; + if ((seq < wrap_around_test_boundary && other.seq >= wrap_around_test_boundary) + || (seq >= wrap_around_test_boundary && other.seq < wrap_around_test_boundary)) { + /* Match the cases where exactly one of the sequence numbers "may have" + * wrapped around. + * + * Examples: + * 1. this->seq = 65530, other.seq = 10 // Did wrap around + * 2. this->seq = 5002, other.seq = 4990 // Not wrapped around + * + * Add 5000 to both sequence numbers to force wrap around so they can be + * compared. This should be fine to do to case 2 as well, as long as the + * addend (5000) is not too large to cause one of them to wrap around. + * + * In practice, we should be unlikely to hit the case where + * + * this->seq = 65530, other.seq = 5001 + * + * because we shouldn't receive more than 5000 payloads in one batch, unless + * the voice courier thread is super slow. Also remember that the timestamp + * is compared first, and payloads this far apart shouldn't have the same + * timestamp. + */ + + /* Casts here ensure the sum wraps around and not implicitly converted to + * wider types. + */ + return static_cast(seq + wrap_around_test_boundary) + > static_cast(other.seq + wrap_around_test_boundary); + } else { + return seq > other.seq; + } +} + +} diff --git a/src/dpp/voice/enabled/write_ready.cpp b/src/dpp/voice/enabled/write_ready.cpp new file mode 100644 index 0000000000..46c0307055 --- /dev/null +++ b/src/dpp/voice/enabled/write_ready.cpp @@ -0,0 +1,115 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include + +#include "../../dave/encryptor.h" + +#include "enabled.h" + +namespace dpp { + +void discord_voice_client::write_ready() { + uint64_t duration = 0; + bool track_marker_found = false; + uint64_t bufsize = 0; + send_audio_type_t type = satype_recorded_audio; + { + std::lock_guard lock(this->stream_mutex); + if (!this->paused && outbuf.size()) { + type = send_audio_type; + if (outbuf[0].packet.size() == sizeof(uint16_t) && (*(reinterpret_cast(outbuf[0].packet.data()))) == AUDIO_TRACK_MARKER) { + outbuf.erase(outbuf.begin()); + track_marker_found = true; + if (tracks > 0) { + tracks--; + } + } + if (outbuf.size()) { + if (this->udp_send(outbuf[0].packet.data(), outbuf[0].packet.length()) == (int)outbuf[0].packet.length()) { + duration = outbuf[0].duration * timescale; + bufsize = outbuf[0].packet.length(); + outbuf.erase(outbuf.begin()); + } + } + } + } + if (duration) { + if (type == satype_recorded_audio) { + std::chrono::nanoseconds latency = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - last_timestamp); + std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) - latency; + if (sleep_time.count() > 0) { + std::this_thread::sleep_for(sleep_time); + } + } + else if (type == satype_overlap_audio) { + std::chrono::nanoseconds latency = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - last_timestamp); + std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) + last_sleep_remainder - latency; + std::chrono::nanoseconds sleep_increment = (std::chrono::nanoseconds(duration) - latency) / AUDIO_OVERLAP_SLEEP_SAMPLES; + if (sleep_time.count() > 0) { + uint16_t samples_count = 0; + std::chrono::nanoseconds overshoot_accumulator{}; + + do { + std::chrono::high_resolution_clock::time_point start_sleep = std::chrono::high_resolution_clock::now(); + std::this_thread::sleep_for(sleep_increment); + std::chrono::high_resolution_clock::time_point end_sleep = std::chrono::high_resolution_clock::now(); + + samples_count++; + overshoot_accumulator += std::chrono::duration_cast(end_sleep - start_sleep) - sleep_increment; + sleep_time -= std::chrono::duration_cast(end_sleep - start_sleep); + } while (std::chrono::nanoseconds(overshoot_accumulator.count() / samples_count) + sleep_increment < sleep_time); + last_sleep_remainder = sleep_time; + } else { + last_sleep_remainder = std::chrono::nanoseconds(0); + } + } + + last_timestamp = std::chrono::high_resolution_clock::now(); + if (!creator->on_voice_buffer_send.empty()) { + voice_buffer_send_t snd(nullptr, ""); + snd.buffer_size = bufsize; + snd.packets_left = outbuf.size(); + snd.voice_client = this; + creator->on_voice_buffer_send.call(snd); + } + } + if (track_marker_found) { + if (!creator->on_voice_track_marker.empty()) { + voice_track_marker_t vtm(nullptr, ""); + vtm.voice_client = this; + { + std::lock_guard lock(this->stream_mutex); + if (!track_meta.empty()) { + vtm.track_meta = track_meta[0]; + track_meta.erase(track_meta.begin()); + } + } + creator->on_voice_track_marker.call(vtm); + } + } +} + + +} diff --git a/src/dpp/voice/stub/stub.h b/src/dpp/voice/stub/stub.h new file mode 100644 index 0000000000..92b95f4e4c --- /dev/null +++ b/src/dpp/voice/stub/stub.h @@ -0,0 +1,65 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct OpusDecoder {}; +struct OpusEncoder {}; +struct OpusRepacketizer {}; +namespace dpp::dave { + struct Session {}; + struct encryptor {}; + struct decryptor {}; +}; +namespace dpp { + struct dave_state {}; + struct audio_mixer {}; +} diff --git a/src/dpp/voice/stub/stubs.cpp b/src/dpp/voice/stub/stubs.cpp new file mode 100644 index 0000000000..b184367d98 --- /dev/null +++ b/src/dpp/voice/stub/stubs.cpp @@ -0,0 +1,102 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include + +#include "stub.h" + +namespace dpp { + + discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host, bool enable_dave) + : websocket_client(_host.substr(0, _host.find(':')), _host.substr(_host.find(':') + 1, _host.length()), "/?v=" + std::to_string(voice_protocol_version), OP_TEXT) + { + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); + } + + void discord_voice_client::voice_courier_loop(discord_voice_client& client, courier_shared_state_t& shared_state) { + } + + void discord_voice_client::cleanup(){ + } + + void discord_voice_client::run() { + } + + void discord_voice_client::thread_run() { + } + + bool discord_voice_client::voice_payload::operator<(const voice_payload& other) const { + return false; + } + + bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcode) { + return false; + } + + void discord_voice_client::read_ready() { + } + + void discord_voice_client::write_ready() { + } + + discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, const size_t length) { + return *this; + } + + discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length) { + return *this; + } + + discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { + return *this; + } + + dpp::socket discord_voice_client::want_write() { + return INVALID_SOCKET; + } + + dpp::socket discord_voice_client::want_read() { + return INVALID_SOCKET; + } + + + void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { + } + + int discord_voice_client::udp_send(const char* data, size_t length) { + return -1; + } + + int discord_voice_client::udp_recv(char* data, size_t max_length) { + return -1; + } + + size_t discord_voice_client::encode(uint8_t *input, size_t inDataSize, uint8_t *output, size_t &outDataSize) { + return 0; + } + + std::string discord_voice_client::discover_ip() { + return ""; + } + +} diff --git a/src/dpp/wsclient.cpp b/src/dpp/wsclient.cpp index 295bbf9e35..424c34d2b1 100644 --- a/src/dpp/wsclient.cpp +++ b/src/dpp/wsclient.cpp @@ -61,7 +61,7 @@ void websocket_client::connect() { state = HTTP_HEADERS; /* Send headers synchronously */ - this->write( + this->socket_write( "GET " + this->path + " HTTP/1.1\r\n" "Host: " + this->hostname + "\r\n" "pragma: no-cache\r\n" @@ -73,7 +73,7 @@ void websocket_client::connect() ); } -bool websocket_client::handle_frame(const std::string& buffer) +bool websocket_client::handle_frame(const std::string& buffer, ws_opcode opcode) { /* This is a stub for classes that derive the websocket client */ return true; @@ -111,17 +111,22 @@ size_t websocket_client::fill_header(unsigned char* outbuf, size_t sendlength, w } -void websocket_client::write(const std::string_view data) +void websocket_client::write(const std::string_view data, ws_opcode _opcode) { + if ((_opcode == OP_AUTO ? this->data_opcode : _opcode) == OP_TEXT) { + log(dpp::ll_trace, std::string("W: ") + data.data()); + } else { + log(dpp::ll_trace, "W: size=" + std::to_string(data.length())); + } if (state == HTTP_HEADERS) { /* Simple write */ - ssl_client::write(data); + ssl_client::socket_write(data); } else { unsigned char out[MAXHEADERSIZE]; - size_t s = this->fill_header(out, data.length(), this->data_opcode); + size_t s = this->fill_header(out, data.length(), _opcode == OP_AUTO ? this->data_opcode : _opcode); std::string header((const char*)out, s); - ssl_client::write(header); - ssl_client::write(data); + ssl_client::socket_write(header); + ssl_client::socket_write(data); } } @@ -175,7 +180,7 @@ bool websocket_client::handle_buffer(std::string& buffer) } } else if (state == CONNECTED) { /* Process packets until we can't (buffer will erase data until parseheader returns false) */ - while (this->parseheader(buffer)){} + while (this->parseheader(buffer)) { } } return true; @@ -249,7 +254,7 @@ bool websocket_client::parseheader(std::string& data) handle_ping(data.substr(payloadstartoffset, len)); } else if ((opcode & ~WS_FINBIT) != OP_PONG) { /* Otherwise, handle everything else apart from a PONG. */ /* Pass this frame to the deriving class */ - this->handle_frame(data.substr(payloadstartoffset, len)); + this->handle_frame(data.substr(payloadstartoffset, len), static_cast(opcode & ~WS_FINBIT)); } /* Remove this frame from the input buffer */ @@ -286,8 +291,8 @@ void websocket_client::one_second_timer() std::string payload = "keepalive"; size_t s = this->fill_header(out, payload.length(), OP_PING); std::string header((const char*)out, s); - ssl_client::write(header); - ssl_client::write(payload); + ssl_client::socket_write(header); + ssl_client::socket_write(payload); } } @@ -297,8 +302,8 @@ void websocket_client::handle_ping(const std::string &payload) unsigned char out[MAXHEADERSIZE]; size_t s = this->fill_header(out, payload.length(), OP_PONG); std::string header((const char*)out, s); - ssl_client::write(header); - ssl_client::write(payload); + ssl_client::socket_write(header); + ssl_client::socket_write(payload); } void websocket_client::send_close_packet() @@ -312,8 +317,8 @@ void websocket_client::send_close_packet() size_t s = this->fill_header(out, payload.length(), OP_CLOSE); std::string header((const char*)out, s); - ssl_client::write(header); - ssl_client::write(payload); + ssl_client::socket_write(header); + ssl_client::socket_write(payload); } void websocket_client::error(uint32_t errorcode) diff --git a/testdata/Robot.pcm b/testdata/Robot.pcm index f9a7525d4626cae46e41ab3244b9de0f99383d1e..e7c167a754f4362bf08c2295cf2884b0a17f372f 100755 GIT binary patch literal 2104292 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

qRi!H>aXp_<|Rk$sVE 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­yp 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%0DlN^X!<%ZlWH{TW-+e~8{wTU;e;7{3l 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 )}O&k|JkSvz8CWrcje7ZcB(xw=pYN9%-{!{HD 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

KwMf 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%0DYk3=EIU9;gJzFM&7yeu3Hk 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

1YeTa8(ChIY)n_7_MhkM9p3Tm{A>8gNeuCS{ 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 literal 149504 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νhpnAU6tI36y!EOytGYozPW@uKbeaa~+hHAd* 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 Date: Tue, 8 Oct 2024 12:46:50 +0000 Subject: [PATCH 49/99] officially deprecate commandhandler --- include/dpp/commandhandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dpp/commandhandler.h b/include/dpp/commandhandler.h index 724f38f577..4a68343996 100644 --- a/include/dpp/commandhandler.h +++ b/include/dpp/commandhandler.h @@ -253,7 +253,7 @@ struct DPP_EXPORT command_info_t { * functions. * @deprecated commandhandler and message commands are deprecated and dpp::slashcommand is encouraged as a replacement. */ -class DPP_EXPORT commandhandler { +class DPP_EXPORT DPP_DEPRECATED("commandhandler should not be used. Plese consider using dpp::cluster::register_command instead.") commandhandler { private: /** * @brief List of guild commands to bulk register From 588213897ba618b5b08500cd04b23bcc490e6146 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Tue, 8 Oct 2024 12:55:24 +0000 Subject: [PATCH 50/99] fix: spelling --- include/dpp/commandhandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dpp/commandhandler.h b/include/dpp/commandhandler.h index 4a68343996..1958bc43d4 100644 --- a/include/dpp/commandhandler.h +++ b/include/dpp/commandhandler.h @@ -253,7 +253,7 @@ struct DPP_EXPORT command_info_t { * functions. * @deprecated commandhandler and message commands are deprecated and dpp::slashcommand is encouraged as a replacement. */ -class DPP_EXPORT DPP_DEPRECATED("commandhandler should not be used. Plese consider using dpp::cluster::register_command instead.") commandhandler { +class DPP_EXPORT DPP_DEPRECATED("commandhandler should not be used. Please consider using dpp::cluster::register_command instead.") commandhandler { private: /** * @brief List of guild commands to bulk register From 09c530bd01389a673efc11e3b2592f601d58cc31 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Tue, 8 Oct 2024 13:34:25 +0000 Subject: [PATCH 51/99] this cant be fatal while we are offering documents on deprecated stuff for SEO --- docpages/example_code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docpages/example_code/CMakeLists.txt b/docpages/example_code/CMakeLists.txt index 87c7713f2b..57f4fee152 100644 --- a/docpages/example_code/CMakeLists.txt +++ b/docpages/example_code/CMakeLists.txt @@ -33,7 +33,7 @@ project(documentation_tests) string(ASCII 27 Esc) -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDPP_CORO -std=c++20 -pthread -O0 -fPIC -rdynamic -DFMT_HEADER_ONLY -Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDPP_CORO -std=c++20 -pthread -O0 -fPIC -rdynamic -DFMT_HEADER_ONLY -Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter -Wno-deprecated-declarations") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") file(GLOB example_list ./*.cpp) From 62d39d5c2ae54e9c52dfc256428453762d71fdfe Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Tue, 8 Oct 2024 19:08:38 +0000 Subject: [PATCH 52/99] docs: simple readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b6507929ea..7dcc630fc5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ D++ is a lightweight and efficient library for **Discord** written in **modern C * Sharding and clustering (Many shards, one process: specify the number of shards, or let the library decide) * Highly optimised ETF (Erlang Term Format) support for very fast websocket throughput * [Slash Commands/Interactions support](https://dpp.dev/slashcommands.html) -* [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio) +* [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio) with DAVE(https://daveprotocol.com) End-To-End Encryption * The entire Discord API is available for use in the library * Stable [Windows support](https://dpp.dev/buildwindows.html) * Ready-made compiled packages for Windows, Raspberry Pi (ARM64/ARM7/ARMv6), Debian x86/x64, and RPM based distributions From 0746aecd5e3ea64fed8c6522b780d53042b4f301 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Tue, 8 Oct 2024 19:09:05 +0000 Subject: [PATCH 53/99] docs: simple readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7dcc630fc5..f2ae8a4bd7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ D++ is a lightweight and efficient library for **Discord** written in **modern C * Sharding and clustering (Many shards, one process: specify the number of shards, or let the library decide) * Highly optimised ETF (Erlang Term Format) support for very fast websocket throughput * [Slash Commands/Interactions support](https://dpp.dev/slashcommands.html) -* [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio) with DAVE(https://daveprotocol.com) End-To-End Encryption +* [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio) with [DAVE](https://daveprotocol.com) End-To-End Encryption * The entire Discord API is available for use in the library * Stable [Windows support](https://dpp.dev/buildwindows.html) * Ready-made compiled packages for Windows, Raspberry Pi (ARM64/ARM7/ARMv6), Debian x86/x64, and RPM based distributions From 4062965e2a96759e0fb6c94f038bb3c35a5e0f56 Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 22:27:38 +0200 Subject: [PATCH 54/99] try to fix formatting --- include/dpp/cluster.h | 70 +++++++++++++++++++++++++++++++++++++++++++ src/dpp/cluster.cpp | 60 +++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 4dad2327f2..39641f98ca 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -133,6 +133,38 @@ class DPP_EXPORT cluster { */ timer_next_t next_timer; + /** + * @brief Mutex to work with named_commands and synchronize read write access + */ + std::shared_mutex named_commands_mutex; + + /** + * @brief Typedef for slashcommand handler type + */ + using slashcommand_handler_t = std::function; + +#ifdef DPP_CORO + /** + * @brief Typedef for coroutines based slashcommand handler type + */ + using co_slashcommand_handler_t = std::function(const slashcommand_t&)>; + + /** + * @brief Typedef for variant of coroutines based slashcommand handler type and regular version of it + */ + using slashcommand_handler_variant = std::variant; + + /** + * @brief Container to store relation between command name and it's handler + */ + std::map named_commands; +#else + /** + * @brief Container to store relation between command name and it's handler + */ + std::map named_commands; +#endif + /** * @brief Tick active timers */ @@ -436,6 +468,44 @@ class DPP_EXPORT cluster { /* Functions for attaching to event handlers */ + /** + * @brief Register a slash command handler. + * + * @param name The name of the slash command to register + * @param handler A handler function of type `slashcommand_handler_t` + * + * @return bool Returns `true` if the command was registered successfully, or `false` if + * the command with the same name already exists + */ + bool register_command(const std::string& name, const slashcommand_handler_t handler); + +#ifdef DPP_CORO + /** + * @brief Register a coroutine-based slash command handler. + * + * @param name The name of the slash command to register. + * @param handler A coroutine handler function of type `co_slashcommand_handler_t`. + * + * @return bool Returns `true` if the command was registered successfully, or `false` if + * the command with the same name already exists. + */ + bool co_register_command(const std::string& name, const co_slashcommand_handler_t handler); +#endif + + /** + * @brief Unregister a slash command. + * + * This function unregisters (removes) a previously registered slash command by name. + * If the command is successfully removed, it returns `true`. + * + * @param name The name of the slash command to unregister. + * + * @return bool Returns `true` if the command was successfully unregistered, or `false` + * if the command was not found. + */ + bool unregister_command(const std::string& name); + + /** * @brief on voice state update event * diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index ff7345428c..3399536ef3 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -120,6 +120,40 @@ cluster::cluster(const std::string &_token, uint32_t _intents, uint32_t _shards, i_message_content, "You have attached an event to cluster::on_message_update() but have not specified the privileged intent dpp::i_message_content. Message content, embeds, attachments, and components on received guild messages will be empty.") ); + + /* Add slashcommand callback for named commands. */ +#ifdef DPP_CORO + on_slashcommand([this](const slashcommand_t& event) -> task { + slashcommand_handler_variant copy; + { + std::shared_lock lk(named_commands_mutex); + auto it = named_commands.find(event.command.get_command_name()); + if (it == named_commands.end()) { + co_return; // Command not found + } + copy = it->second; + } + if (std::holds_alternative(copy)) { + co_await std::get(copy)(event); + } else if (std::holds_alternative(copy)) { + std::get(copy)(event); + } + co_return; + }); +#else + on_slashcommand([this](const slashcommand_t& event) { + slashcommand_handler_t copy; + { + std::shared_lock lk(named_commands_mutex); + auto it = named_commands.find(event.command.get_command_name()); + if (it == named_commands.end()) { + return; // Command not found + } + copy = it->second; + } + copy(event); + }); +#endif } cluster::~cluster() @@ -466,4 +500,30 @@ cluster& cluster::set_request_timeout(uint16_t timeout) { return *this; } +bool cluster::register_command(const std::string &name, const slashcommand_handler_t handler) { + std::unique_lock lk(named_commands_mutex); + if (named_commands.count(name) != 0) { + return false; + } + named_commands.emplace(name, handler); + return true; +} + +#ifdef DPP_CORO +bool cluster::co_register_command(const std::string& name, const co_slashcommand_handler_t handler) { + std::unique_lock lk(named_commands_mutex); + if (named_commands.count(name) != 0) { + return false; + } + named_commands.emplace(name, handler); + return true; +} +#endif + +bool cluster::unregister_command(const std::string &name) { + std::unique_lock lk(named_commands_mutex); + return named_commands.erase(name) == 1; +} + + }; From 2d1f71bffd6c1a3ac7f13c962d6a137bd29f177e Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 22:52:15 +0200 Subject: [PATCH 55/99] fix with templates --- include/dpp/cluster.h | 11 ++++++++++- src/dpp/cluster.cpp | 11 ----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 39641f98ca..3e817711da 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -489,7 +489,16 @@ class DPP_EXPORT cluster { * @return bool Returns `true` if the command was registered successfully, or `false` if * the command with the same name already exists. */ - bool co_register_command(const std::string& name, const co_slashcommand_handler_t handler); + template + std::enable_if_t, dpp::task>, bool> + register_command(const std::string& name, F&& handler){ + std::unique_lock lk(named_commands_mutex); + if (named_commands.count(name) != 0) { + return false; + } + named_commands.emplace(name, handler); + return true; + }; #endif /** diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 3399536ef3..36a60d249c 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -509,17 +509,6 @@ bool cluster::register_command(const std::string &name, const slashcommand_handl return true; } -#ifdef DPP_CORO -bool cluster::co_register_command(const std::string& name, const co_slashcommand_handler_t handler) { - std::unique_lock lk(named_commands_mutex); - if (named_commands.count(name) != 0) { - return false; - } - named_commands.emplace(name, handler); - return true; -} -#endif - bool cluster::unregister_command(const std::string &name) { std::unique_lock lk(named_commands_mutex); return named_commands.erase(name) == 1; From 90fb093e550d626998e5064f478982f3b7653b97 Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 23:06:24 +0200 Subject: [PATCH 56/99] remove comments --- src/dpp/cluster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 36a60d249c..105bab0bf2 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -129,7 +129,7 @@ cluster::cluster(const std::string &_token, uint32_t _intents, uint32_t _shards, std::shared_lock lk(named_commands_mutex); auto it = named_commands.find(event.command.get_command_name()); if (it == named_commands.end()) { - co_return; // Command not found + co_return; } copy = it->second; } @@ -147,7 +147,7 @@ cluster::cluster(const std::string &_token, uint32_t _intents, uint32_t _shards, std::shared_lock lk(named_commands_mutex); auto it = named_commands.find(event.command.get_command_name()); if (it == named_commands.end()) { - return; // Command not found + return; } copy = it->second; } From bad343db0347705675b2fe2401cf0969ffdf1d40 Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 23:07:31 +0200 Subject: [PATCH 57/99] fix other thing --- include/dpp/cluster.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 3e817711da..8c96862f2f 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -495,7 +495,7 @@ class DPP_EXPORT cluster { std::unique_lock lk(named_commands_mutex); if (named_commands.count(name) != 0) { return false; - } + } named_commands.emplace(name, handler); return true; }; From a8306527b3b4a2f17821846a447c040f49b38b0a Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 23:08:11 +0200 Subject: [PATCH 58/99] fix other thing --- src/dpp/cluster.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 105bab0bf2..b08a5a1885 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -514,5 +514,4 @@ bool cluster::unregister_command(const std::string &name) { return named_commands.erase(name) == 1; } - }; From 083e204d23668f520331af9d73ff8696375d0514 Mon Sep 17 00:00:00 2001 From: ruslan-ilesik Date: Tue, 8 Oct 2024 23:08:39 +0200 Subject: [PATCH 59/99] fix other thing --- include/dpp/cluster.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 8c96862f2f..4e8734b125 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -514,7 +514,6 @@ class DPP_EXPORT cluster { */ bool unregister_command(const std::string& name); - /** * @brief on voice state update event * From 376870f7f6c3ee8ac646fe3de561e521f4ecd6ed Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Tue, 8 Oct 2024 22:28:24 +0100 Subject: [PATCH 60/99] style: indentation of lambdas --- src/dpp/cluster.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index b08a5a1885..544902ade1 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -126,12 +126,12 @@ cluster::cluster(const std::string &_token, uint32_t _intents, uint32_t _shards, on_slashcommand([this](const slashcommand_t& event) -> task { slashcommand_handler_variant copy; { - std::shared_lock lk(named_commands_mutex); - auto it = named_commands.find(event.command.get_command_name()); - if (it == named_commands.end()) { - co_return; - } - copy = it->second; + std::shared_lock lk(named_commands_mutex); + auto it = named_commands.find(event.command.get_command_name()); + if (it == named_commands.end()) { + co_return; + } + copy = it->second; } if (std::holds_alternative(copy)) { co_await std::get(copy)(event); @@ -144,12 +144,12 @@ cluster::cluster(const std::string &_token, uint32_t _intents, uint32_t _shards, on_slashcommand([this](const slashcommand_t& event) { slashcommand_handler_t copy; { - std::shared_lock lk(named_commands_mutex); - auto it = named_commands.find(event.command.get_command_name()); - if (it == named_commands.end()) { - return; - } - copy = it->second; + std::shared_lock lk(named_commands_mutex); + auto it = named_commands.find(event.command.get_command_name()); + if (it == named_commands.end()) { + return; + } + copy = it->second; } copy(event); }); From 2a36704a87c5aa01e8fc5a3e0800931111563a5b Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 9 Oct 2024 00:01:46 +0100 Subject: [PATCH 61/99] refactor: better registration with try_emplace --- src/dpp/cluster.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 544902ade1..26e333d194 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -502,11 +502,8 @@ cluster& cluster::set_request_timeout(uint16_t timeout) { bool cluster::register_command(const std::string &name, const slashcommand_handler_t handler) { std::unique_lock lk(named_commands_mutex); - if (named_commands.count(name) != 0) { - return false; - } - named_commands.emplace(name, handler); - return true; + auto [_, inserted] = named_commands.try_emplace(name, handler); + return inserted; } bool cluster::unregister_command(const std::string &name) { From 08b3841a8cf362d97fcea64c178dc12eeeb19a54 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 9 Oct 2024 00:02:56 +0100 Subject: [PATCH 62/99] Update cluster.h --- include/dpp/cluster.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 4e8734b125..787b95d854 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -493,11 +493,8 @@ class DPP_EXPORT cluster { std::enable_if_t, dpp::task>, bool> register_command(const std::string& name, F&& handler){ std::unique_lock lk(named_commands_mutex); - if (named_commands.count(name) != 0) { - return false; - } - named_commands.emplace(name, handler); - return true; + auto [_, inserted] = named_commands.try_emplace(name, handler); + return inserted; }; #endif From 95270f523199ff5b463872fc9fdcf911534258cf Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 9 Oct 2024 00:08:42 +0100 Subject: [PATCH 63/99] refactor: std::forward --- include/dpp/cluster.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 787b95d854..0b6a980e65 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -493,7 +493,7 @@ class DPP_EXPORT cluster { std::enable_if_t, dpp::task>, bool> register_command(const std::string& name, F&& handler){ std::unique_lock lk(named_commands_mutex); - auto [_, inserted] = named_commands.try_emplace(name, handler); + auto [_, inserted] = named_commands.try_emplace(name, std::forward(handler)); return inserted; }; #endif From 74db5ee90ea6653b27462f7b8d19dfa08a5fb445 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Fri, 11 Oct 2024 08:00:02 +0100 Subject: [PATCH 64/99] refactor: why you so salty? Entirely remove libsodium from D++ (#1265) --- .github/workflows/ci.yml | 4 +- .github/workflows/test-docs-examples.yml | 2 +- Dockerfile | 2 +- README.md | 5 +- buildtools/classes/Packager/Vcpkg.php | 1 - cmake/ARM64ToolChain.cmake | 3 +- cmake/ARMv7ToolChain.cmake | 4 +- cmake/CPackSetup.cmake | 4 +- cmake/FindSodium.cmake | 293 ------------------ cmake/LINUXx86ToolChain.cmake | 2 +- cmake/Win32Toolchain.cmake | 5 - docpages/01_frequently_asked_questions.md | 6 +- docpages/advanced_reference/voice_model.md | 8 +- docpages/building/freebsd.md | 10 +- docpages/building/openbsd.md | 2 +- docpages/building/osx.md | 4 +- docpages/images/audioframe.svg | 4 +- docpages/install/install-windows-vs-zip.md | 2 +- docpages/make_a_bot/windows_vs.md | 2 +- docpages/make_a_bot/windows_wsl.md | 2 +- include/dpp/cluster.h | 2 +- include/dpp/discordvoiceclient.h | 16 +- include/dpp/exception.h | 5 +- include/dpp/utility.h | 2 +- library-vcpkg/CMakeLists.txt | 2 - library/CMakeLists.txt | 38 +-- src/davetest/dave.cpp | 3 + src/dpp/discordvoiceclient.cpp | 2 - src/dpp/voice/enabled/audio_mix.cpp | 2 - src/dpp/voice/enabled/constructor.cpp | 9 - src/dpp/voice/enabled/enabled.h | 48 ++- src/dpp/voice/enabled/handle_frame.cpp | 2 + src/dpp/voice/enabled/opus.cpp | 17 +- src/dpp/voice/enabled/read_ready.cpp | 2 +- src/dpp/voice/enabled/xchacha20.cpp | 234 ++++++++++++++ vcpkg/ports/dpp/vcpkg.json | 1 - win32/32/bin/libsodium.dll | Bin 336896 -> 0 bytes win32/bin/libsodium.dll | Bin 330752 -> 0 bytes win32/include/sodium.h | 69 ----- win32/include/sodium/core.h | 28 -- win32/include/sodium/crypto_aead_aes256gcm.h | 179 ----------- .../sodium/crypto_aead_chacha20poly1305.h | 180 ----------- .../sodium/crypto_aead_xchacha20poly1305.h | 100 ------ win32/include/sodium/crypto_auth.h | 46 --- win32/include/sodium/crypto_auth_hmacsha256.h | 70 ----- win32/include/sodium/crypto_auth_hmacsha512.h | 68 ---- .../sodium/crypto_auth_hmacsha512256.h | 65 ---- win32/include/sodium/crypto_box.h | 177 ----------- .../crypto_box_curve25519xchacha20poly1305.h | 164 ---------- .../crypto_box_curve25519xsalsa20poly1305.h | 112 ------- win32/include/sodium/crypto_core_ed25519.h | 100 ------ win32/include/sodium/crypto_core_hchacha20.h | 36 --- win32/include/sodium/crypto_core_hsalsa20.h | 36 --- .../include/sodium/crypto_core_ristretto255.h | 100 ------ win32/include/sodium/crypto_core_salsa20.h | 36 --- win32/include/sodium/crypto_core_salsa2012.h | 36 --- win32/include/sodium/crypto_core_salsa208.h | 40 --- win32/include/sodium/crypto_generichash.h | 84 ----- .../sodium/crypto_generichash_blake2b.h | 118 ------- win32/include/sodium/crypto_hash.h | 40 --- win32/include/sodium/crypto_hash_sha256.h | 60 ---- win32/include/sodium/crypto_hash_sha512.h | 60 ---- win32/include/sodium/crypto_kdf.h | 53 ---- win32/include/sodium/crypto_kdf_blake2b.h | 44 --- win32/include/sodium/crypto_kx.h | 66 ---- win32/include/sodium/crypto_onetimeauth.h | 65 ---- .../sodium/crypto_onetimeauth_poly1305.h | 72 ----- win32/include/sodium/crypto_pwhash.h | 147 --------- win32/include/sodium/crypto_pwhash_argon2i.h | 122 -------- win32/include/sodium/crypto_pwhash_argon2id.h | 122 -------- .../crypto_pwhash_scryptsalsa208sha256.h | 120 ------- win32/include/sodium/crypto_scalarmult.h | 46 --- .../sodium/crypto_scalarmult_curve25519.h | 42 --- .../sodium/crypto_scalarmult_ed25519.h | 51 --- .../sodium/crypto_scalarmult_ristretto255.h | 43 --- win32/include/sodium/crypto_secretbox.h | 93 ------ .../crypto_secretbox_xchacha20poly1305.h | 70 ----- .../crypto_secretbox_xsalsa20poly1305.h | 69 ----- .../crypto_secretstream_xchacha20poly1305.h | 108 ------- win32/include/sodium/crypto_shorthash.h | 41 --- .../sodium/crypto_shorthash_siphash24.h | 50 --- win32/include/sodium/crypto_sign.h | 107 ------- win32/include/sodium/crypto_sign_ed25519.h | 124 -------- .../crypto_sign_edwards25519sha512batch.h | 55 ---- win32/include/sodium/crypto_stream.h | 59 ---- win32/include/sodium/crypto_stream_chacha20.h | 106 ------- win32/include/sodium/crypto_stream_salsa20.h | 61 ---- .../include/sodium/crypto_stream_salsa2012.h | 53 ---- win32/include/sodium/crypto_stream_salsa208.h | 56 ---- .../include/sodium/crypto_stream_xchacha20.h | 61 ---- win32/include/sodium/crypto_stream_xsalsa20.h | 61 ---- win32/include/sodium/crypto_verify_16.h | 23 -- win32/include/sodium/crypto_verify_32.h | 23 -- win32/include/sodium/crypto_verify_64.h | 23 -- win32/include/sodium/export.h | 57 ---- win32/include/sodium/randombytes.h | 72 ----- .../sodium/randombytes_internal_random.h | 22 -- win32/include/sodium/randombytes_sysrandom.h | 19 -- win32/include/sodium/runtime.h | 52 ---- win32/include/sodium/utils.h | 179 ----------- win32/include/sodium/version.h | 33 -- 101 files changed, 339 insertions(+), 5085 deletions(-) delete mode 100644 cmake/FindSodium.cmake create mode 100644 src/dpp/voice/enabled/xchacha20.cpp delete mode 100755 win32/32/bin/libsodium.dll delete mode 100644 win32/bin/libsodium.dll delete mode 100644 win32/include/sodium.h delete mode 100644 win32/include/sodium/core.h delete mode 100644 win32/include/sodium/crypto_aead_aes256gcm.h delete mode 100644 win32/include/sodium/crypto_aead_chacha20poly1305.h delete mode 100644 win32/include/sodium/crypto_aead_xchacha20poly1305.h delete mode 100644 win32/include/sodium/crypto_auth.h delete mode 100644 win32/include/sodium/crypto_auth_hmacsha256.h delete mode 100644 win32/include/sodium/crypto_auth_hmacsha512.h delete mode 100644 win32/include/sodium/crypto_auth_hmacsha512256.h delete mode 100644 win32/include/sodium/crypto_box.h delete mode 100644 win32/include/sodium/crypto_box_curve25519xchacha20poly1305.h delete mode 100644 win32/include/sodium/crypto_box_curve25519xsalsa20poly1305.h delete mode 100644 win32/include/sodium/crypto_core_ed25519.h delete mode 100644 win32/include/sodium/crypto_core_hchacha20.h delete mode 100644 win32/include/sodium/crypto_core_hsalsa20.h delete mode 100644 win32/include/sodium/crypto_core_ristretto255.h delete mode 100644 win32/include/sodium/crypto_core_salsa20.h delete mode 100644 win32/include/sodium/crypto_core_salsa2012.h delete mode 100644 win32/include/sodium/crypto_core_salsa208.h delete mode 100644 win32/include/sodium/crypto_generichash.h delete mode 100644 win32/include/sodium/crypto_generichash_blake2b.h delete mode 100644 win32/include/sodium/crypto_hash.h delete mode 100644 win32/include/sodium/crypto_hash_sha256.h delete mode 100644 win32/include/sodium/crypto_hash_sha512.h delete mode 100644 win32/include/sodium/crypto_kdf.h delete mode 100644 win32/include/sodium/crypto_kdf_blake2b.h delete mode 100644 win32/include/sodium/crypto_kx.h delete mode 100644 win32/include/sodium/crypto_onetimeauth.h delete mode 100644 win32/include/sodium/crypto_onetimeauth_poly1305.h delete mode 100644 win32/include/sodium/crypto_pwhash.h delete mode 100644 win32/include/sodium/crypto_pwhash_argon2i.h delete mode 100644 win32/include/sodium/crypto_pwhash_argon2id.h delete mode 100644 win32/include/sodium/crypto_pwhash_scryptsalsa208sha256.h delete mode 100644 win32/include/sodium/crypto_scalarmult.h delete mode 100644 win32/include/sodium/crypto_scalarmult_curve25519.h delete mode 100644 win32/include/sodium/crypto_scalarmult_ed25519.h delete mode 100644 win32/include/sodium/crypto_scalarmult_ristretto255.h delete mode 100644 win32/include/sodium/crypto_secretbox.h delete mode 100644 win32/include/sodium/crypto_secretbox_xchacha20poly1305.h delete mode 100644 win32/include/sodium/crypto_secretbox_xsalsa20poly1305.h delete mode 100644 win32/include/sodium/crypto_secretstream_xchacha20poly1305.h delete mode 100644 win32/include/sodium/crypto_shorthash.h delete mode 100644 win32/include/sodium/crypto_shorthash_siphash24.h delete mode 100644 win32/include/sodium/crypto_sign.h delete mode 100644 win32/include/sodium/crypto_sign_ed25519.h delete mode 100644 win32/include/sodium/crypto_sign_edwards25519sha512batch.h delete mode 100644 win32/include/sodium/crypto_stream.h delete mode 100644 win32/include/sodium/crypto_stream_chacha20.h delete mode 100644 win32/include/sodium/crypto_stream_salsa20.h delete mode 100644 win32/include/sodium/crypto_stream_salsa2012.h delete mode 100644 win32/include/sodium/crypto_stream_salsa208.h delete mode 100644 win32/include/sodium/crypto_stream_xchacha20.h delete mode 100644 win32/include/sodium/crypto_stream_xsalsa20.h delete mode 100644 win32/include/sodium/crypto_verify_16.h delete mode 100644 win32/include/sodium/crypto_verify_32.h delete mode 100644 win32/include/sodium/crypto_verify_64.h delete mode 100644 win32/include/sodium/export.h delete mode 100644 win32/include/sodium/randombytes.h delete mode 100644 win32/include/sodium/randombytes_internal_random.h delete mode 100644 win32/include/sodium/randombytes_sysrandom.h delete mode 100644 win32/include/sodium/runtime.h delete mode 100644 win32/include/sodium/utils.h delete mode 100644 win32/include/sodium/version.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b034bcd83..00579aefac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: sudo apt-add-repository -y "deb http://apt.llvm.org/$osname/ llvm-toolchain-$osname-${{ matrix.cfg.version }} main" - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y ${{ matrix.cfg.package }} pkg-config libsodium-dev libopus-dev zlib1g-dev rpm + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y ${{ matrix.cfg.package }} pkg-config libopus-dev zlib1g-dev rpm - name: Generate CMake run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release ${{matrix.cfg.cmake-flags}} @@ -150,7 +150,7 @@ jobs: xcode-version: ${{ matrix.cfg.xcode-version }} - name: Install homebrew packages - run: brew install cmake make libsodium opus openssl pkg-config + run: brew install cmake make opus openssl pkg-config - name: Generate CMake run: cmake -B build -DDPP_NO_VCPKG=ON -DCMAKE_BUILD_TYPE=Release -DDPP_CORO=ON -DAVX_TYPE=AVX0 diff --git a/.github/workflows/test-docs-examples.yml b/.github/workflows/test-docs-examples.yml index 4b5dfb4758..648916d6b3 100644 --- a/.github/workflows/test-docs-examples.yml +++ b/.github/workflows/test-docs-examples.yml @@ -35,7 +35,7 @@ jobs: submodules: recursive - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-12 libsodium-dev libopus-dev zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev libopusfile-dev + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-12 libopus-dev zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev libopusfile-dev - name: Generate CMake run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DDPP_CORO=ON -DCMAKE_BUILD_TYPE=Debug .. diff --git a/Dockerfile b/Dockerfile index 780c2e2af9..5ae726414a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:noble@sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b -RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libsodium-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/DPP diff --git a/README.md b/README.md index f2ae8a4bd7..f0a658892a 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,9 @@ Other compilers may work (either newer versions of those listed above, or differ #### Optional Dependencies -For **voice support** you require both of: +For **voice support** you require: * [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! +* Note that our **windows zips** come packaged with copies of this library - you do not need to install it yourself! ### Included Dependencies (Packaged with the library) diff --git a/buildtools/classes/Packager/Vcpkg.php b/buildtools/classes/Packager/Vcpkg.php index 1790cbefc2..f677ba6675 100644 --- a/buildtools/classes/Packager/Vcpkg.php +++ b/buildtools/classes/Packager/Vcpkg.php @@ -170,7 +170,6 @@ function constructPortAndVersionFile(string $sha512 = "0"): string "license": "Apache-2.0", "supports": "((windows & !static & !uwp) | linux | osx)", "dependencies": [ - "libsodium", "nlohmann-json", "openssl", "opus", diff --git a/cmake/ARM64ToolChain.cmake b/cmake/ARM64ToolChain.cmake index 8087e3f375..d9caf02693 100644 --- a/cmake/ARM64ToolChain.cmake +++ b/cmake/ARM64ToolChain.cmake @@ -47,6 +47,5 @@ EXECUTE_PROCESS(COMMAND sudo mv TMPFILE /etc/apt/sources.list) EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture arm64) EXECUTE_PROCESS(COMMAND sudo apt-add-repository -y ppa:canonical-kernel-team/ppa) EXECUTE_PROCESS(COMMAND sudo apt update) -EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu libc6-dev-arm64-cross zlib1g-dev:arm64 libssl-dev:arm64 libopus-dev:arm64 libsodium-dev:arm64) -EXECUTE_PROCESS(COMMAND sudo mv /usr/lib/aarch64-linux-gnu/pkgconfig/libsodium.pc /usr/lib/pkgconfig/) +EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-aarch64-linux-gnu g++-8-aarch64-linux-gnu libc6-dev-arm64-cross zlib1g-dev:arm64 libssl-dev:arm64 libopus-dev:arm64) diff --git a/cmake/ARMv7ToolChain.cmake b/cmake/ARMv7ToolChain.cmake index 7b9bacf3bc..215df7e0ce 100644 --- a/cmake/ARMv7ToolChain.cmake +++ b/cmake/ARMv7ToolChain.cmake @@ -46,6 +46,4 @@ EXECUTE_PROCESS(COMMAND printf "deb [arch=amd64] http://archive.ubuntu.com/ubunt EXECUTE_PROCESS(COMMAND sudo mv TMPFILE /etc/apt/sources.list) EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture armhf) EXECUTE_PROCESS(COMMAND sudo apt update) -EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf zlib1g-dev:armhf libssl-dev:armhf libopus-dev:armhf libsodium-dev:armhf) -EXECUTE_PROCESS(COMMAND sudo mv /usr/lib/arm-linux-gnueabihf/pkgconfig/libsodium.pc /usr/lib/pkgconfig/) - +EXECUTE_PROCESS(COMMAND sudo apt install -y cmake gcc-8-arm-linux-gnueabihf g++-8-arm-linux-gnueabihf zlib1g-dev:armhf libssl-dev:armhf libopus-dev:armhf) diff --git a/cmake/CPackSetup.cmake b/cmake/CPackSetup.cmake index fcdcf156af..047b7600ff 100644 --- a/cmake/CPackSetup.cmake +++ b/cmake/CPackSetup.cmake @@ -50,8 +50,8 @@ set(CPACK_FREEBSD_PACKAGE_MAINTAINER "bsd@dpp.dev") set(CPACK_FREEBSD_PACKAGE_ORIGIN "misc/libdpp") set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0") set(CPACK_PACKAGE_CONTACT "https://discord.gg/dpp") # D++ Development Discord -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libsodium23 (>= 1.0.17-1), libopus0 (>= 1.3-1)") -set(CPACK_RPM_PACKAGE_REQUIRES "libsodium >= 1.0.20-1, opus >= 1.3.1") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "libopus0 (>= 1.3-1)") +set(CPACK_RPM_PACKAGE_REQUIRES "opus >= 1.3.1") set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "An incredibly lightweight C++ Discord library") set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SECTION "libs") diff --git a/cmake/FindSodium.cmake b/cmake/FindSodium.cmake deleted file mode 100644 index fbcc45ad11..0000000000 --- a/cmake/FindSodium.cmake +++ /dev/null @@ -1,293 +0,0 @@ -# Written in 2016 by Henrik Steffen Gaßmann -# -# To the extent possible under law, the author(s) have dedicated all copyright -# and related and neighboring rights to this software to the public domain -# worldwide. This software is distributed without any warranty. -# -# You should have received a copy of the CC0 Public Domain Dedication along with -# this software. If not, see -# -# http://creativecommons.org/publicdomain/zero/1.0/ -# -# ############################################################################## -# Tries to find the local libsodium installation. -# -# On Windows the sodium_DIR environment variable is used as a default hint which -# can be overridden by setting the corresponding cmake variable. -# -# Once done the following variables will be defined: -# -# sodium_FOUND sodium_INCLUDE_DIR sodium_LIBRARY_DEBUG sodium_LIBRARY_RELEASE -# sodium_VERSION_STRING -# -# Furthermore an imported "sodium" target is created. -# - -if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") - set(_GCC_COMPATIBLE 1) -endif() - -# static library option -if(NOT DEFINED sodium_USE_STATIC_LIBS) - option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF) -endif() -if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST)) - unset(sodium_LIBRARY CACHE) - unset(sodium_LIBRARY_DEBUG CACHE) - unset(sodium_LIBRARY_RELEASE CACHE) - unset(sodium_DLL_DEBUG CACHE) - unset(sodium_DLL_RELEASE CACHE) - set(sodium_USE_STATIC_LIBS_LAST - ${sodium_USE_STATIC_LIBS} - CACHE INTERNAL "internal change tracking variable") -endif() - -# ############################################################################## -# UNIX -if(UNIX) - # import pkg-config - find_package(PkgConfig) - if(PKG_CONFIG_FOUND) - pkg_check_modules(sodium_PKG QUIET libsodium) - endif() - - if(sodium_USE_STATIC_LIBS) - if(sodium_PKG_STATIC_LIBRARIES) - foreach(_libname ${sodium_PKG_STATIC_LIBRARIES}) - if(NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending - # with .a - list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a") - endif() - endforeach() - list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES) - else() - # if pkgconfig for libsodium doesn't provide static lib info, then - # override PKG_STATIC here.. - set(sodium_PKG_STATIC_LIBRARIES libsodium.a) - endif() - - set(XPREFIX sodium_PKG_STATIC) - else() - if(sodium_PKG_LIBRARIES STREQUAL "") - set(sodium_PKG_LIBRARIES sodium) - endif() - - set(XPREFIX sodium_PKG) - endif() - - find_path(sodium_INCLUDE_DIR sodium.h HINTS ${${XPREFIX}_INCLUDE_DIRS}) - find_library(sodium_LIBRARY_DEBUG - NAMES ${${XPREFIX}_LIBRARIES} - HINTS ${${XPREFIX}_LIBRARY_DIRS}) - find_library(sodium_LIBRARY_RELEASE - NAMES ${${XPREFIX}_LIBRARIES} - HINTS ${${XPREFIX}_LIBRARY_DIRS}) - - # ############################################################################ - # Windows -elseif(WIN32) - set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory") - mark_as_advanced(sodium_DIR) - - find_path(sodium_INCLUDE_DIR sodium.h - HINTS ${sodium_DIR} - PATH_SUFFIXES include) - - if(MSVC) - # detect target architecture - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.cpp" [=[ - #if defined _M_IX86 - #error ARCH_VALUE x86_32 - #elif defined _M_X64 - #error ARCH_VALUE x86_64 - #endif - #error ARCH_VALUE unknown - ]=]) - try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}/arch.cpp" - OUTPUT_VARIABLE _COMPILATION_LOG) - string(REGEX - REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*" - "\\1" - _TARGET_ARCH - "${_COMPILATION_LOG}") - - # construct library path - if(_TARGET_ARCH STREQUAL "x86_32") - string(APPEND _PLATFORM_PATH "Win32") - elseif(_TARGET_ARCH STREQUAL "x86_64") - string(APPEND _PLATFORM_PATH "x64") - else() - message( - FATAL_ERROR - "the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake." - ) - endif() - string(APPEND _PLATFORM_PATH "/$$CONFIG$$") - - if(MSVC_VERSION LESS 1900) - math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60") - else() - math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50") - endif() - string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}") - - if(sodium_USE_STATIC_LIBS) - string(APPEND _PLATFORM_PATH "/static") - else() - string(APPEND _PLATFORM_PATH "/dynamic") - endif() - - string(REPLACE "$$CONFIG$$" - "Debug" - _DEBUG_PATH_SUFFIX - "${_PLATFORM_PATH}") - string(REPLACE "$$CONFIG$$" - "Release" - _RELEASE_PATH_SUFFIX - "${_PLATFORM_PATH}") - - find_library(sodium_LIBRARY_DEBUG libsodium.lib - HINTS ${sodium_DIR} - PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) - find_library(sodium_LIBRARY_RELEASE libsodium.lib - HINTS ${sodium_DIR} - PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) - if(NOT sodium_USE_STATIC_LIBS) - set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") - find_library(sodium_DLL_DEBUG libsodium - HINTS ${sodium_DIR} - PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX}) - find_library(sodium_DLL_RELEASE libsodium - HINTS ${sodium_DIR} - PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK}) - endif() - - elseif(_GCC_COMPATIBLE) - if(sodium_USE_STATIC_LIBS) - find_library(sodium_LIBRARY_DEBUG libsodium.a - HINTS ${sodium_DIR} - PATH_SUFFIXES lib) - find_library(sodium_LIBRARY_RELEASE libsodium.a - HINTS ${sodium_DIR} - PATH_SUFFIXES lib) - else() - find_library(sodium_LIBRARY_DEBUG libsodium.dll.a - HINTS ${sodium_DIR} - PATH_SUFFIXES lib) - find_library(sodium_LIBRARY_RELEASE libsodium.dll.a - HINTS ${sodium_DIR} - PATH_SUFFIXES lib) - - file(GLOB _DLL - LIST_DIRECTORIES false - RELATIVE "${sodium_DIR}/bin" - "${sodium_DIR}/bin/libsodium*.dll") - find_library(sodium_DLL_DEBUG ${_DLL} libsodium - HINTS ${sodium_DIR} - PATH_SUFFIXES bin) - find_library(sodium_DLL_RELEASE ${_DLL} libsodium - HINTS ${sodium_DIR} - PATH_SUFFIXES bin) - endif() - else() - message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") - endif() - - # ############################################################################ - # unsupported -else() - message(FATAL_ERROR "this platform is not supported by FindSodium.cmake") -endif() - -# ############################################################################## -# common stuff - -# extract sodium version -if(sodium_INCLUDE_DIR) - set(_VERSION_HEADER "${sodium_INCLUDE_DIR}/sodium/version.h") - if(EXISTS "${_VERSION_HEADER}") - file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT) - string( - REGEX - REPLACE - ".*#define[ \t]*SODIUM_VERSION_STRING[ \t]*\"([^\n]*)\".*" - "\\1" - sodium_VERSION_STRING - "${_VERSION_HEADER_CONTENT}") - set(sodium_VERSION_STRING "${sodium_VERSION_STRING}") - endif() -endif() - -# communicate results -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(sodium - REQUIRED_VARS - sodium_LIBRARY_RELEASE - sodium_LIBRARY_DEBUG - sodium_INCLUDE_DIR - VERSION_VAR - sodium_VERSION_STRING) - -# mark file paths as advanced -mark_as_advanced(sodium_INCLUDE_DIR) -mark_as_advanced(sodium_LIBRARY_DEBUG) -mark_as_advanced(sodium_LIBRARY_RELEASE) -if(WIN32) - mark_as_advanced(sodium_DLL_DEBUG) - mark_as_advanced(sodium_DLL_RELEASE) -endif() - -# create imported target -if(sodium_USE_STATIC_LIBS) - set(_LIB_TYPE STATIC) -else() - set(_LIB_TYPE SHARED) -endif() -add_library(sodium ${_LIB_TYPE} IMPORTED) - -set_target_properties(sodium - PROPERTIES INTERFACE_INCLUDE_DIRECTORIES - "${sodium_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LANGUAGES - "C") - -if(sodium_USE_STATIC_LIBS) - set_target_properties(sodium - PROPERTIES INTERFACE_COMPILE_DEFINITIONS - "SODIUM_STATIC" - IMPORTED_LOCATION - "${sodium_LIBRARY_RELEASE}" - IMPORTED_LOCATION_DEBUG - "${sodium_LIBRARY_DEBUG}") -else() - if(UNIX) - set_target_properties(sodium - PROPERTIES IMPORTED_LOCATION - "${sodium_LIBRARY_RELEASE}" - IMPORTED_LOCATION_DEBUG - "${sodium_LIBRARY_DEBUG}") - elseif(WIN32) - set_target_properties(sodium - PROPERTIES IMPORTED_IMPLIB - "${sodium_LIBRARY_RELEASE}" - IMPORTED_IMPLIB_DEBUG - "${sodium_LIBRARY_DEBUG}") - if(NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND")) - set_target_properties(sodium - PROPERTIES IMPORTED_LOCATION_DEBUG - "${sodium_DLL_DEBUG}") - endif() - if(NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND")) - set_target_properties(sodium - PROPERTIES IMPORTED_LOCATION_RELWITHDEBINFO - "${sodium_DLL_RELEASE}" - IMPORTED_LOCATION_MINSIZEREL - "${sodium_DLL_RELEASE}" - IMPORTED_LOCATION_RELEASE - "${sodium_DLL_RELEASE}") - endif() - endif() -endif() diff --git a/cmake/LINUXx86ToolChain.cmake b/cmake/LINUXx86ToolChain.cmake index 240eb269aa..e943b2aafd 100644 --- a/cmake/LINUXx86ToolChain.cmake +++ b/cmake/LINUXx86ToolChain.cmake @@ -26,7 +26,7 @@ set(T_AVX_EXITCODE "0" CACHE STRING INTERNAL FORCE) EXECUTE_PROCESS(COMMAND sudo dpkg --add-architecture i386) EXECUTE_PROCESS(COMMAND sudo apt-get update) -EXECUTE_PROCESS(COMMAND sudo apt-get install -qq -y g++-10 gcc-10-multilib glibc-*:i386 libc6-dev-i386 g++-10-multilib zlib1g-dev:i386 libssl-dev:i386 libopus-dev:i386 libsodium-dev:i386) +EXECUTE_PROCESS(COMMAND sudo apt-get install -qq -y g++-10 gcc-10-multilib glibc-*:i386 libc6-dev-i386 g++-10-multilib zlib1g-dev:i386 libssl-dev:i386 libopus-dev:i386) EXECUTE_PROCESS(COMMAND export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig/) set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") diff --git a/cmake/Win32Toolchain.cmake b/cmake/Win32Toolchain.cmake index 7b1ab655ad..ec20c1ab8a 100644 --- a/cmake/Win32Toolchain.cmake +++ b/cmake/Win32Toolchain.cmake @@ -10,17 +10,12 @@ ADD_DEFINITIONS(/bigobj) link_libraries("${PROJECT_SOURCE_DIR}/win32/32/lib/libssl.lib") link_libraries("${PROJECT_SOURCE_DIR}/win32/32/lib/libcrypto.lib") link_libraries("${PROJECT_SOURCE_DIR}/win32/32/lib/zlib.lib") -link_libraries("${PROJECT_SOURCE_DIR}/win32/32/lib/libsodium.lib") link_libraries("${PROJECT_SOURCE_DIR}/win32/32/lib/opus.lib") set(OPUS_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/win32/include") set(OPUS_LIBRARIES "${PROJECT_SOURCE_DIR}/win32/32/lib/opus.lib") -set(sodium_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/win32/include") -set(sodium_LIBRARY_DEBUG "${PROJECT_SOURCE_DIR}/win32/32/lib/libsodium.lib") -set(sodium_LIBRARY_RELEASE "${PROJECT_SOURCE_DIR}/win32/32/lib/libsodium.lib") set(HAVE_OPUS_OPUS_H "${PROJECT_SOURCE_DIR}/win32/include/opus/opus.h") set(OPUS_FOUND 1) -SET(sodium_VERSION_STRING "win32 bundled") include_directories("${PROJECT_SOURCE_DIR}/win32/include") diff --git a/docpages/01_frequently_asked_questions.md b/docpages/01_frequently_asked_questions.md index 8c82b46f6d..62336d6ff9 100644 --- a/docpages/01_frequently_asked_questions.md +++ b/docpages/01_frequently_asked_questions.md @@ -68,7 +68,7 @@ All functions within D++ are multi-threaded. You should still avoid doing long o ## Does this library support voice? -Yes! This library supports voice and will automatically enable voice if your system has the libopus and libsodium libraries. When running `cmake` the script will identify if these libraries are found. See the example programs for information on how to send audio. +Yes! This library supports voice and will automatically enable voice if your system has the libopus library. When running `cmake` the script will identify if this library is found. See the example programs for information on how to send audio. ## Does this library support sharding? @@ -94,10 +94,6 @@ No, the library only requires C++17. We have some optional features such as \ref To fix this issue, run `ldconfig`: `sudo ldconfig` as root. Log out if your SSH session and log back in, and the bot should be able to find the library. -## When compiling with voice support, I get an error: "No rule to make target 'sodium_LIBRARY_DEBUG-NOTFOUND', needed by 'libdpp.so'. Stop." - -The libsodium package requires pkg-config, but does not check for it when installed. Install it as root, e.g. `sudo apt install pkg-config`. Rerun cmake, and rebuild the library. - ## When I try to instantiate a dpp::cluster in windows, I get "D++ Debug/Release mismatch" If this happens, ensure you are using the correct precompiled build of the library. Our precompiled binaries are built in two forms, **release mode** and **debug mode** for Visual Studio 2019/2022. These two versions of the library are not cross-compatible due to differences in the debug and release STL (Microsoft standard library implementation). You should not need to build your own copy, but please see the section about \ref buildwindows for more information on how to build your own copy, if needed. diff --git a/docpages/advanced_reference/voice_model.md b/docpages/advanced_reference/voice_model.md index ca4525d174..15864fa0ed 100644 --- a/docpages/advanced_reference/voice_model.md +++ b/docpages/advanced_reference/voice_model.md @@ -11,7 +11,7 @@ initial connection to this secondary websocket. Every connection to a voice chan 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. +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 libssl. 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, @@ -153,9 +153,9 @@ digraph "Example Directory" { "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"; + "AES AEAD encryption\nof OPUS stream\nusing ratchet" -> "XChaCha20-Poly1305 encryption"; + "Dave encryption off" -> "XChaCha20-Poly1305 encryption"; + "XChaCha20-Poly1305 encryption" -> "UDP sendto"; "UDP sendto" -> "Discord RTP server"; "DAVE enabled" -> "MLS send key package"; "MLS send key package" -> "MLS receive external sender"; diff --git a/docpages/building/freebsd.md b/docpages/building/freebsd.md index f8ca1a87e1..b6ec50ed99 100644 --- a/docpages/building/freebsd.md +++ b/docpages/building/freebsd.md @@ -12,21 +12,13 @@ pkg install cmake ## 2. Install Voice Dependencies (Optional) -If you wish to use voice support, you'll need to install opus and libsodium: +If you wish to use voice support, you'll need to install opus: -First, you need to install opus. ```bash cd /usr/ports/audio/opus make && make install ``` -Then, you need to install libsodium. - -```bash -cd /usr/ports/security/libsodium -make && make install -``` - ## 3. Build Source Code ```bash diff --git a/docpages/building/openbsd.md b/docpages/building/openbsd.md index a289d75f13..34953cccc9 100644 --- a/docpages/building/openbsd.md +++ b/docpages/building/openbsd.md @@ -15,7 +15,7 @@ pkg_add cmake If you wish to use voice support, you'll need to do the following: ```bash -pkg_add libsodium opus pkgconf +pkg_add opus ``` ## 3. Build Source Code diff --git a/docpages/building/osx.md b/docpages/building/osx.md index b43a99e9e1..059c77fca0 100644 --- a/docpages/building/osx.md +++ b/docpages/building/osx.md @@ -15,10 +15,10 @@ brew install openssl pkgconfig \note Usually, you do not need pkgconfig. However, it seems that it throws errors about openssl without. -For voice support, additional dependencies are required: +For voice support, additional dependency is required: ```bash -brew install libsodium opus +brew install opus ``` ## 3. Build Source Code diff --git a/docpages/images/audioframe.svg b/docpages/images/audioframe.svg index 302f65b0db..b17e104c49 100755 --- a/docpages/images/audioframe.svg +++ b/docpages/images/audioframe.svg @@ -173,7 +173,7 @@ sodipodi:role="line" id="tspan3010" x="748.91284" - y="835.92316">DAVE (AES 128 GCM AEAD) + y="835.92316">DAVE OPUS AUDIO (AES 128 GCM AEAD) SODIUM (CHACHA20 POLY1305) + y="912.60059">RTP CONTENT (CHACHA20 POLY1305 AEAD) __cdecl `int __cdecl main( 1>...\windows-bot-template-main\x64\Debug\MyBot.exe : fatal error LNK1120: 1 unresolved externals 1>Done building project "MyBot.vcxproj" -- FAILED. \endcode Make sure your don't have another version of the library installed through vcpkg. The template uses a slightly different version of D++ that has coroutines, while the vcpkg version does not, and the latter overwrites it! Uninstalling the library through vcpkg should fix this issue. -- If you get an error that a DLL is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all DLLs from the **bin** directory of where you cloned the D++ repository to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these DLL files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), `libsodium.dll` and `opus.dll`. Note the template project does this for you, so you should never encounter this issue. +- If you get an error that a DLL is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all DLLs from the **bin** directory of where you cloned the D++ repository to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these DLL files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), and `opus.dll`. Note the template project does this for you, so you should never encounter this issue. - If you get an error that says "Debug/Release mismatch", **you are using the wrong configuration of the D++ dll**. Your bot's executable and the dpp.dll file should both be built in the same configuration (Release or Debug), you get this error if they are different. **This also means you altered the template in a significant way,** we recommend you undo your modifications or reinstall the template. - Stuck? You can find us on the [official Discord server](https://discord.gg/dpp) - ask away! We don't bite! diff --git a/docpages/make_a_bot/windows_wsl.md b/docpages/make_a_bot/windows_wsl.md index 455073bb20..e09ea7400e 100644 --- a/docpages/make_a_bot/windows_wsl.md +++ b/docpages/make_a_bot/windows_wsl.md @@ -8,7 +8,7 @@ This tutorial teaches you how to create a lightweight environment for D++ develo 2. Now open PowerShell as Administrator and type `wsl` to start up your subsystem. You may also type `ubuntu` into your search bar and open it that way. 3. Head on over to your home directory using `cd ~`. 4. Download the latest build for your distro using `wget [url here]`. In this guide we will use the latest build for 64 bit Ubuntu: `wget -O libdpp.deb https://dl.dpp.dev/latest`. -5. Finally install all required dependencies and the library itself using `sudo apt-get install libopus0 libopus-dev libsodium-dev && sudo dpkg -i libdpp.deb && rm libdpp.deb`. +5. Finally install all required dependencies and the library itself using `sudo apt-get install libopus0 libopus-dev && sudo dpkg -i libdpp.deb && rm libdpp.deb`. 6. Congratulations, you've successfully installed all dependencies! Now comes the real fun: Setting up the environment! For this tutorial we'll use a as small as possible setup, so you might create a more advanced one for production bots. 7. Create a new directory, inside your home directory, using `mkdir MyBot`. Then, you want to open that directory using `cd MyBot`. 8. Now that you've a directory to work in, type `touch mybot.cxx` to create a file you can work in! diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 0b6a980e65..5264d83d30 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -1321,7 +1321,7 @@ class DPP_EXPORT cluster { /** * @brief Called when packets are sent from the voice buffer. * The voice buffer contains packets that are already encoded with Opus and encrypted - * with Sodium, and merged into packets by the repacketizer, which is done in the + * with XChaCha20-Poly1305, and merged into packets by the repacketizer, which is done in the * dpp::discord_voice_client::send_audio method. You should use the buffer size properties * of dpp::voice_buffer_send_t to determine if you should fill the buffer with more * content. diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 9edeef94fa..69e0abd7f8 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -134,7 +134,7 @@ enum dave_version_t : uint8_t { */ dave_version_none = 0, /** - * @brief DAVE enabled, version 1 (E2EE encryption on top of sodium) + * @brief DAVE enabled, version 1 (E2EE encryption on top of openssl) */ dave_version_1 = 1, }; @@ -685,12 +685,6 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ class dpp::cluster* creator; - /** - * @brief This needs to be static, we only initialise libsodium once per program start, - * so initialising it on first use in a voice connection is best. - */ - static bool sodium_initialised; - /** * @brief True when the thread is shutting down */ @@ -865,7 +859,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * @param _session_id The voice session id to identify with * @param _host The voice server hostname to connect to (hostname:port format) * @param enable_dave Enable DAVE E2EE - * @throw dpp::voice_exception Sodium or Opus failed to initialise, or D++ is not compiled with voice support + * @throw dpp::voice_exception Opus failed to initialise, or D++ is not compiled with voice support * @warning DAVE E2EE is an EXPERIMENTAL feature! */ discord_voice_client(dpp::cluster* _cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host, bool enable_dave = false); @@ -900,7 +894,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * * You should send an audio packet of `send_audio_raw_max_length` (11520) bytes. * Note that this function can be costly as it has to opus encode - * the PCM audio on the fly, and also encrypt it with libsodium. + * the PCM audio on the fly, and also encrypt it with openssl. * * @note Because this function encrypts and encodes packets before * pushing them onto the output queue, if you have a complete stream @@ -940,7 +934,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * Some containers such as .ogg may contain OPUS * encoded data already. In this case, we don't need to encode the * frames using opus here. We can bypass the codec, only applying - * libsodium to the stream. + * openssl to the stream. * * @param opus_packet Opus packets. Discord expects opus frames * to be encoded at 48000Hz @@ -968,7 +962,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * Some containers such as .ogg may contain OPUS * encoded data already. In this case, we don't need to encode the * frames using opus here. We can bypass the codec, only applying - * libsodium to the stream. + * opens to the stream. * * Duration is calculated internally * diff --git a/include/dpp/exception.h b/include/dpp/exception.h index 9584e8e86d..1c60084240 100644 --- a/include/dpp/exception.h +++ b/include/dpp/exception.h @@ -31,7 +31,7 @@ namespace dpp { * @brief Exception error codes possible for dpp::exception::code() * * This list is a combined list of Discord's error codes, HTTP error codes, - * zlib, opus, sodium and C library codes (e.g. DNS, socket etc). You may + * zlib, opus and C library codes (e.g. DNS, socket etc). You may * use these to easily identify a type of exception without having to resort * to string comparison against dpp::exception::what() * @@ -98,7 +98,6 @@ enum exception_error_code { err_no_voice_support = 29, err_invalid_voice_packet_length = 30, err_opus = 31, - err_sodium = 32, err_etf = 33, err_cache = 34, err_icon_size = 35, @@ -591,6 +590,8 @@ class exception : public std::exception derived_exception(file_exception, exception); derived_exception(connection_exception, exception); derived_exception(voice_exception, exception); + derived_exception(encryption_exception, voice_exception); + derived_exception(decryption_exception, voice_exception); derived_exception(rest_exception, exception); derived_exception(invalid_token_exception, rest_exception); derived_exception(length_exception, exception); diff --git a/include/dpp/utility.h b/include/dpp/utility.h index 0dcb974972..6654606fc3 100644 --- a/include/dpp/utility.h +++ b/include/dpp/utility.h @@ -574,7 +574,7 @@ double DPP_EXPORT time_f(); /** * @brief Returns true if D++ was built with voice support * - * @return bool True if voice support is compiled in (libsodium/libopus) + * @return bool True if voice support is compiled in (libopus) */ bool DPP_EXPORT has_voice(); diff --git a/library-vcpkg/CMakeLists.txt b/library-vcpkg/CMakeLists.txt index 0d7d0ac995..3148b6163d 100644 --- a/library-vcpkg/CMakeLists.txt +++ b/library-vcpkg/CMakeLists.txt @@ -108,7 +108,6 @@ target_link_options( find_package(nlohmann_json CONFIG REQUIRED) find_package(OpenSSL REQUIRED) find_package(Opus CONFIG REQUIRED) -find_package(unofficial-sodium CONFIG REQUIRED) find_package(ZLIB REQUIRED) target_link_libraries( @@ -117,7 +116,6 @@ target_link_libraries( $<$:OpenSSL::SSL> $<$:OpenSSL::Crypto> $<$:Opus::opus> - $<$:unofficial-sodium::sodium> $<$:ZLIB::ZLIB> $<$:Threads::Threads> ) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 5d328f295c..0cabd74161 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -63,17 +63,12 @@ if(WIN32 AND NOT MINGW) link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libssl.lib") link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libcrypto.lib") link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/zlib.lib") - link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libsodium.lib") link_libraries("${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/opus.lib") set(OPUS_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../win32/include") set(OPUS_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/opus.lib") - set(sodium_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../win32/include") - set(sodium_LIBRARY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libsodium.lib") - set(sodium_LIBRARY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libsodium.lib") set(HAVE_OPUS_OPUS_H "${CMAKE_CURRENT_SOURCE_DIR}/../win32/include/opus/opus.h") set(OPUS_FOUND 1) - SET(sodium_VERSION_STRING "win32 bundled") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../win32/include") @@ -123,7 +118,6 @@ if(NOT BUILD_SHARED_LIBS) endif() set(OPENSSL_USE_STATIC_LIBS ON) - set(sodium_USE_STATIC_LIBS ON) set(OPUS_USE_STATIC_LIBS TRUE) else() message(WARNING "-- Building of static library not supported on non UNIX systems.") @@ -132,30 +126,19 @@ endif() if (BUILD_VOICE_SUPPORT) if (MINGW OR NOT WIN32) - find_package(PkgConfig QUIET) - if(PKG_CONFIG_FOUND) - include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindSodium.cmake") - else() - message("-- Could not detect ${Green}libsodium${ColourReset} due to missing ${Green}pkgconfig${ColourReset}. VOICE support will be ${Red}disabled${ColourReset}") - endif() - include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindOpus.cmake") + include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindOpus.cmake") endif() - if(DEFINED OPUS_FOUND) + if(HAVE_OPUS_OPUS_H) message("-- Found Opus ${Green}${OPUS_LIBRARIES}${ColourReset}") - if((WIN32 OR PKG_CONFIG_FOUND) AND DEFINED sodium_VERSION_STRING AND DEFINED sodium_LIBRARY_RELEASE) - add_compile_definitions(HAVE_VOICE) - - message("-- Sodium ${Green}${sodium_VERSION_STRING}${ColourReset}") - - set(HAVE_VOICE 1) - endif() + add_compile_definitions(HAVE_VOICE) + set(HAVE_VOICE 1) endif() if(HAVE_VOICE) - message("-- Detected ${Green}libsodium${ColourReset} and ${Green}libopus${ColourReset}. VOICE support will be ${Green}enabled${ColourReset}") + message("-- Detected ${Green}libopus${ColourReset}. VOICE support will be ${Green}enabled${ColourReset}") else(HAVE_VOICE) - message("-- Could not detect ${Green}libsodium${ColourReset} and/or ${Green}libopus${ColourReset}. VOICE support will be ${Red}disabled${ColourReset}") + message("-- Could not detect ${Green}libopus${ColourReset}. VOICE support will be ${Red}disabled${ColourReset}") endif(HAVE_VOICE) else() message("-- Voice support disabled by cmake option") @@ -275,13 +258,11 @@ foreach (fullmodname ${subdirlist}) if (NOT WINDOWS_32_BIT) target_link_libraries(${modname} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libssl.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libcrypto.lib" - "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/libsodium.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/opus.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/lib/zlib.lib") else() target_link_libraries(${modname} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/lib/libssl.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/lib/libcrypto.lib" - "${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/lib/libsodium.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/lib/opus.lib" "${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/lib/zlib.lib") endif() @@ -305,9 +286,8 @@ foreach (fullmodname ${subdirlist}) endif() if (HAVE_VOICE) - target_link_libraries(${modname} PUBLIC ${sodium_LIBRARY_RELEASE} ${OPUS_LIBRARIES}) - - include_directories(${OPUS_INCLUDE_DIRS} ${sodium_INCLUDE_DIR}) + target_link_libraries(${modname} PUBLIC ${OPUS_LIBRARIES}) + include_directories(${OPUS_INCLUDE_DIRS}) endif() endforeach() @@ -425,13 +405,11 @@ if(WIN32 AND NOT MINGW) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/bin/zlib1.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/bin/libcrypto-1_1-x64.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/bin/libssl-1_1-x64.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/bin/libsodium.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/bin/opus.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) else() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/bin/zlib1.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/bin/libcrypto-1_1.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/bin/libssl-1_1.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/bin/libsodium.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../win32/32/bin/opus.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" COPYONLY) endif() endif() diff --git a/src/davetest/dave.cpp b/src/davetest/dave.cpp index 719dd1e06b..94812e0d89 100644 --- a/src/davetest/dave.cpp +++ b/src/davetest/dave.cpp @@ -71,6 +71,9 @@ int main() { if (v && v->is_ready()) { v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); } + dave_test.start_timer([v, &testaudio](auto) { + v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); + }, 15); }); diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index ca44b19c06..64e1598247 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -68,8 +68,6 @@ moving_averager::operator float() { return 0.0f; } -bool discord_voice_client::sodium_initialised = false; - discord_voice_client::~discord_voice_client() { cleanup(); diff --git a/src/dpp/voice/enabled/audio_mix.cpp b/src/dpp/voice/enabled/audio_mix.cpp index a411623f6d..6d0f128e8c 100644 --- a/src/dpp/voice/enabled/audio_mix.cpp +++ b/src/dpp/voice/enabled/audio_mix.cpp @@ -29,8 +29,6 @@ #include #include #include - -#include #include namespace dpp { diff --git a/src/dpp/voice/enabled/constructor.cpp b/src/dpp/voice/enabled/constructor.cpp index 1e0a20b8f3..fc8e16d0d5 100644 --- a/src/dpp/voice/enabled/constructor.cpp +++ b/src/dpp/voice/enabled/constructor.cpp @@ -26,11 +26,8 @@ #include #include #include - -#include #include #include "../../dave/encryptor.h" - #include "enabled.h" namespace dpp { @@ -64,12 +61,6 @@ discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _ch server_id(_server_id), channel_id(_channel_id) { - if (!discord_voice_client::sodium_initialised) { - if (sodium_init() < 0) { - throw dpp::voice_exception(err_sodium, "discord_voice_client::discord_voice_client; sodium_init() failed"); - } - discord_voice_client::sodium_initialised = true; - } int opusError = 0; encoder = opus_encoder_create(opus_sample_rate_hz, opus_channel_count, OPUS_APPLICATION_VOIP, &opusError); if (opusError) { diff --git a/src/dpp/voice/enabled/enabled.h b/src/dpp/voice/enabled/enabled.h index 78b55958d5..ef821f8d66 100644 --- a/src/dpp/voice/enabled/enabled.h +++ b/src/dpp/voice/enabled/enabled.h @@ -52,7 +52,6 @@ #include #include #include -#include #include #include "../../dave/session.h" #include "../../dave/decryptor.h" @@ -99,7 +98,7 @@ struct rtp_header { }; /** -* @brief Transport encryption type (libsodium) +* @brief Transport encryption type (libssl) */ constexpr std::string_view transport_encryption_protocol = "aead_xchacha20_poly1305_rtpsize"; @@ -108,3 +107,48 @@ std::string generate_displayable_code(const std::vector &data, size_t d size_t audio_mix(discord_voice_client &client, audio_mixer &mixer, opus_int32 *pcm_mix, const opus_int16 *pcm, size_t park_count, int samples, int &max_samples); } + +/** + * @brief OpenSSL based reimplementation of sodium's crypto_aead_xchacha20poly1305_ietf_encrypt + * @note Parameters and types are intended to match sodium as to be a drop-in replacement. + * @param c Ciphertext + Tag output + * @param clen Ciphertext length output + * @param m Message (plaintext) input + * @param mlen Message length + * @param ad Additional authenticated data (AAD) + * @param adlen Authenticated data length + * @param nsec Secret nonce (optional, nullptr to not use) + * @param npub Public nonce (24 bytes) + * @param k Key (32 bytes) + * @return 0 on success, -1 on error + */ +int ssl_crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, unsigned long long *clen, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k); + +/** + * @brief OpenSSL based reimplementation of sodium's crypto_aead_xchacha20poly1305_ietf_decrypt + * @note Parameters and types are intended to match sodium as to be a drop-in replacement. + * @param m Message (plaintext) output + * @param mlen message length output + * @param nsec Secret nonce (optional, nullptr to not use) + * @param c Ciphertext + Tag input + * @param clen Ciphertext length + * @param ad Additional authenticated data (AAD) + * @param adlen Additional authenticated data length + * @param npub Public nonce (24 bytes) + * @param k Key (32 bytes) + * @return 0 on success, -1 on error + */ +int ssl_crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, unsigned long long *mlen, unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k); + +/** + * @brief Size of public nonce (24 bytes) + * @note This constant is a drop-in replacement for one in libsodium + */ +inline constexpr unsigned int ssl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES = 24U; + +/** + * @brief AAD size + * @note This constant is a drop-in replacement for one in libsodium + */ +inline constexpr unsigned int ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES = 16U; + diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp index 5ade5ac4f0..060fb9692f 100644 --- a/src/dpp/voice/enabled/handle_frame.cpp +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -363,6 +363,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod auto key_response = mls_state->dave_session->get_marshalled_key_package(); key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); + } else { + ready_now = true; } if (ready_now) { diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp index 066cacdb53..9f8aaeaff9 100644 --- a/src/dpp/voice/enabled/opus.cpp +++ b/src/dpp/voice/enabled/opus.cpp @@ -24,7 +24,6 @@ #include #include #include - #include #include "../../dave/array_view.h" #include "../../dave/encryptor.h" @@ -115,9 +114,10 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet rtp_header header(sequence, timestamp, (uint32_t)ssrc); /* Expected payload size is unencrypted header + encrypted opus packet + unencrypted 32 bit nonce */ - size_t packet_siz = sizeof(header) + (encoded_audio_length + crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); + size_t packet_siz = sizeof(header) + (encoded_audio_length + ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); std::vector payload(packet_siz); + std::vector payload2(packet_siz); /* Set RTP header */ std::memcpy(payload.data(), &header, sizeof(header)); @@ -126,13 +126,14 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet uint32_t noncel = htonl(packet_nonce); /* 24 byte is needed for encrypting, discord just want 4 byte so just fill up the rest with null */ - unsigned char encrypt_nonce[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { '\0' }; + unsigned char encrypt_nonce[ssl_crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = { '\0' }; memcpy(encrypt_nonce, &noncel, sizeof(noncel)); - /* Execute */ - crypto_aead_xchacha20poly1305_ietf_encrypt( + /* Execute */ + unsigned long long int clen{0}; + if (ssl_crypto_aead_xchacha20poly1305_ietf_encrypt( payload.data() + sizeof(header), - nullptr, + &clen, encoded_audio.data(), encoded_audio_length, /* The RTP Header as Additional Data */ @@ -141,7 +142,9 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet nullptr, static_cast(encrypt_nonce), secret_key.data() - ); + ) != 0) { + log(dpp::ll_debug, "XChaCha20 Encryption failed"); + } /* Append the 4 byte nonce to the resulting payload */ std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); diff --git a/src/dpp/voice/enabled/read_ready.cpp b/src/dpp/voice/enabled/read_ready.cpp index 51a817fbed..95ac598160 100644 --- a/src/dpp/voice/enabled/read_ready.cpp +++ b/src/dpp/voice/enabled/read_ready.cpp @@ -120,7 +120,7 @@ void discord_voice_client::read_ready() uint8_t decrypted[65535] = { 0 }; unsigned long long opus_packet_len = 0; - if (crypto_aead_xchacha20poly1305_ietf_decrypt( + if (ssl_crypto_aead_xchacha20poly1305_ietf_decrypt( decrypted, &opus_packet_len, nullptr, ciphertext, ciphertext_len, diff --git a/src/dpp/voice/enabled/xchacha20.cpp b/src/dpp/voice/enabled/xchacha20.cpp new file mode 100644 index 0000000000..cff2cc1eb9 --- /dev/null +++ b/src/dpp/voice/enabled/xchacha20.cpp @@ -0,0 +1,234 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Contains macros from BoringSSL, Copyright (c) 2014, Google Inc. + * Adapted from the public domain, estream code by D. Bernstein. + * + ************************************************************************************/ + +#include +#include +#include +#include +#include "enabled.h" + +/** + * @brief ChaCha static constant + * For some reason this is the ASCII string 'expand 32-byte k'. + * It is specified by the standard, and cannot be changed. + */ +constexpr uint8_t CHACHA20_CONSTANT_SEED[16] = {'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k' }; + +/** + * XChaCha20-Poly1305 key size + */ +constexpr size_t KEY_SIZE = 32; + +/** + * @brief ChaCha20-Poly1305 nonce size + */ +constexpr size_t CHACHA_NONCE_SIZE = 12; + +/** + * @brief Rotates the bits of a 32-bit unsigned integer to the left by a specified number of positions. + * @note From Google's BoringSSL, but made constexpr + * + * @param value value to shift + * @param shift number of bits to shift left by + * @return shifted value + */ +constexpr uint32_t rotl_u32(uint32_t value, int shift) { + return (value << shift) | (value >> ((-shift) & 31)); +} + +/** + * @brief Updates a, b, c, and d with a ChaCha20 quarter round. + * @note This is based on black box voodoo from BoringSSL. + * + * @param x an array forming part of an XChaCha20 nonce + * @param a First word of the quarter-round. + * @param b Second word of the quarter-round. + * @param c Third word of the quarter-round. + * @param d Fourth word of the quarter-round. + */ +constexpr void quarter_round(uint32_t* x, int a, int b, int c, int d) { + x[a] += x[b]; + x[d] = rotl_u32(x[d] ^ x[a], 16); + x[c] += x[d]; + x[b] = rotl_u32(x[b] ^ x[c], 12); + x[a] += x[b]; + x[d] = rotl_u32(x[d] ^ x[a], 8); + x[c] += x[d]; + x[b] = rotl_u32(x[b] ^ x[c], 7); +} + +/** + * @brief key derivation function that takes a 256-bit key and a 128-bit nonce, producing a 256-bit subkey. + * + * This subkey is then used in the XChaCha20 algorithm to extend the nonce size to 192 bits. + * @note This based on the function from BoringSSL. Do not mess with it. + * @param out output 32 byte subkey + * @param key input 32 byte key + * @param nonce input 16 byte nonce + */ +void hchacha20(unsigned char out[KEY_SIZE], const unsigned char key[KEY_SIZE], const unsigned char nonce[16]) { + uint32_t x[16]; + std::memcpy(x, CHACHA20_CONSTANT_SEED, sizeof(CHACHA20_CONSTANT_SEED)); + std::memcpy(&x[4], key, KEY_SIZE); + std::memcpy(&x[CHACHA_NONCE_SIZE], nonce, 16); + for (size_t i = 0; i < 20; i += 2) { + quarter_round(x, 0, 4, 8, 12); + quarter_round(x, 1, 5, 9, 13); + quarter_round(x, 2, 6, 10, 14); + quarter_round(x, 3, 7, 11, 15); + quarter_round(x, 0, 5, 10, 15); + quarter_round(x, 1, 6, 11, 12); + quarter_round(x, 2, 7, 8, 13); + quarter_round(x, 3, 4, 9, 14); + } + std::memcpy(out, &x[0], sizeof(uint32_t) * 4); + std::memcpy(&out[16], &x[CHACHA_NONCE_SIZE], sizeof(uint32_t) * 4); +} + +int ssl_crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, unsigned long long *clen, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k) { + unsigned char sub_key[KEY_SIZE]; + /* Regular ChaCha20-Poly1305 uses 12-byte nonce */ + unsigned char chacha_nonce[CHACHA_NONCE_SIZE] = {0}; + EVP_CIPHER_CTX *ctx = nullptr; + int len = 0; + int ciphertext_len = 0; + + try { + /* Derive the sub-key using HChaCha20 */ + hchacha20(sub_key, k, npub); + + /* Use the last 8 bytes of the 24-byte XChaCha20 nonce */ + std::memcpy(chacha_nonce + 4, npub + ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES, 8); + + /* Initialize encryption context with ChaCha20-Poly1305 */ + ctx = EVP_CIPHER_CTX_new(); + if ((ctx == nullptr) || (EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), nullptr, nullptr, nullptr) == 0)) { + throw dpp::encryption_exception("Error initializing encryption context"); + } + + /* Set key and nonce */ + if (EVP_EncryptInit_ex(ctx, nullptr, nullptr, sub_key, chacha_nonce) == 0) { + throw dpp::encryption_exception("Error setting key and nonce"); + } + + /* Set additional authenticated data (AAD) */ + if (EVP_EncryptUpdate(ctx, nullptr, &len, ad, static_cast(adlen)) == 0) { + throw dpp::encryption_exception("Error setting additional authenticated data"); + } + + /* Encrypt the plaintext */ + if (EVP_EncryptUpdate(ctx, c, &len, m, static_cast(mlen)) == 0) { + throw dpp::encryption_exception("Error during encryption"); + } + ciphertext_len = len; + + if (EVP_EncryptFinal_ex(ctx, c + len, &len) == 0) { + throw dpp::encryption_exception("Error finalizing encryption"); + } + ciphertext_len += len; + + /* Get the authentication tag */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES, c + ciphertext_len) == 0) { + throw dpp::encryption_exception("Error getting authentication tag"); + } + + /* Total ciphertext length (ciphertext + tag) */ + if (clen != nullptr) { + *clen = ciphertext_len + ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES; + } + + } catch (const dpp::encryption_exception& e) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + EVP_CIPHER_CTX_free(ctx); + return 0; +} + +int ssl_crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, unsigned long long *mlen, [[maybe_unused]] unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k) { + unsigned char sub_key[KEY_SIZE]; + /* Regular ChaCha20-Poly1305 uses 12-byte nonce */ + unsigned char chacha_nonce[CHACHA_NONCE_SIZE] = {0}; + EVP_CIPHER_CTX *ctx = nullptr; + int len = 0; + int plaintext_len = 0; + + if (clen < ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES) { + /* Ciphertext length must include at least the tag (16 bytes) */ + return -1; + } + + try { + /* Derive the sub-key using HChaCha20 */ + hchacha20(sub_key, k, npub); + + /* Use the last 8 bytes of the 24-byte XChaCha20 nonce */ + std::memcpy(chacha_nonce + 4, npub + ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES, 8); + + /* Initialize decryption context with ChaCha20-Poly1305 */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx || (EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), nullptr, nullptr, nullptr) == 0)) { + throw dpp::decryption_exception("Error initializing decryption context"); + } + + /* Set key and nonce */ + if (EVP_DecryptInit_ex(ctx, nullptr, nullptr, sub_key, chacha_nonce) == 0) { + throw dpp::decryption_exception("Error setting key and nonce"); + } + + /* Set additional authenticated data (AAD) */ + if (EVP_DecryptUpdate(ctx, nullptr, &len, ad, static_cast(adlen)) == 0) { + throw dpp::decryption_exception("Error setting additional authenticated data"); + } + + /* Decrypt the ciphertext (excluding the tag) */ + if (EVP_DecryptUpdate(ctx, m, &len, c, static_cast(clen - ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES)) == 0) { + throw dpp::decryption_exception("Error during decryption"); + } + plaintext_len = len; + + /* Set the expected tag */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES, const_cast(c + clen - ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES)) == 0) { + throw dpp::decryption_exception("Error setting authentication tag"); + } + + /* Check tag */ + int ret = EVP_DecryptFinal_ex(ctx, m + len, &len); + if (ret > 0) { + /* Tag is valid, finalize plaintext length */ + *mlen = plaintext_len + len; + } else { + throw dpp::decryption_exception("Authentication failed"); + } + + } catch (const dpp::decryption_exception& e) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + EVP_CIPHER_CTX_free(ctx); + return 0; +} diff --git a/vcpkg/ports/dpp/vcpkg.json b/vcpkg/ports/dpp/vcpkg.json index cc9cc114f3..743b89dd0b 100644 --- a/vcpkg/ports/dpp/vcpkg.json +++ b/vcpkg/ports/dpp/vcpkg.json @@ -6,7 +6,6 @@ "license": "Apache-2.0", "supports": "(windows & !static & !uwp) | linux | osx", "dependencies": [ - "libsodium", "nlohmann-json", "openssl", "opus", diff --git a/win32/32/bin/libsodium.dll b/win32/32/bin/libsodium.dll deleted file mode 100755 index 09d2e51792f4ce5c526be8ae54ea9b25566ace22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336896 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

G3H=_ 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 diff --git a/win32/bin/libsodium.dll b/win32/bin/libsodium.dll deleted file mode 100644 index 0fc90b12317a48943978c179dbae522cb3395765..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 330752 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 z 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 z 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�>V1G4zco_7i$?4B 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⪼cCtk{Pm67I!`cD>Vpyw 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 MhyVHee=-CA8xgzU4gdfE diff --git a/win32/include/sodium.h b/win32/include/sodium.h deleted file mode 100644 index 295f911cff..0000000000 --- a/win32/include/sodium.h +++ /dev/null @@ -1,69 +0,0 @@ - -#ifndef sodium_H -#define sodium_H - -#include "sodium/version.h" - -#include "sodium/core.h" -#include "sodium/crypto_aead_aes256gcm.h" -#include "sodium/crypto_aead_chacha20poly1305.h" -#include "sodium/crypto_aead_xchacha20poly1305.h" -#include "sodium/crypto_auth.h" -#include "sodium/crypto_auth_hmacsha256.h" -#include "sodium/crypto_auth_hmacsha512.h" -#include "sodium/crypto_auth_hmacsha512256.h" -#include "sodium/crypto_box.h" -#include "sodium/crypto_box_curve25519xsalsa20poly1305.h" -#include "sodium/crypto_core_hsalsa20.h" -#include "sodium/crypto_core_hchacha20.h" -#include "sodium/crypto_core_salsa20.h" -#include "sodium/crypto_core_salsa2012.h" -#include "sodium/crypto_core_salsa208.h" -#include "sodium/crypto_generichash.h" -#include "sodium/crypto_generichash_blake2b.h" -#include "sodium/crypto_hash.h" -#include "sodium/crypto_hash_sha256.h" -#include "sodium/crypto_hash_sha512.h" -#include "sodium/crypto_kdf.h" -#include "sodium/crypto_kdf_blake2b.h" -#include "sodium/crypto_kx.h" -#include "sodium/crypto_onetimeauth.h" -#include "sodium/crypto_onetimeauth_poly1305.h" -#include "sodium/crypto_pwhash.h" -#include "sodium/crypto_pwhash_argon2i.h" -#include "sodium/crypto_scalarmult.h" -#include "sodium/crypto_scalarmult_curve25519.h" -#include "sodium/crypto_secretbox.h" -#include "sodium/crypto_secretbox_xsalsa20poly1305.h" -#include "sodium/crypto_secretstream_xchacha20poly1305.h" -#include "sodium/crypto_shorthash.h" -#include "sodium/crypto_shorthash_siphash24.h" -#include "sodium/crypto_sign.h" -#include "sodium/crypto_sign_ed25519.h" -#include "sodium/crypto_stream.h" -#include "sodium/crypto_stream_chacha20.h" -#include "sodium/crypto_stream_salsa20.h" -#include "sodium/crypto_stream_xsalsa20.h" -#include "sodium/crypto_verify_16.h" -#include "sodium/crypto_verify_32.h" -#include "sodium/crypto_verify_64.h" -#include "sodium/randombytes.h" -#include "sodium/randombytes_internal_random.h" -#include "sodium/randombytes_sysrandom.h" -#include "sodium/runtime.h" -#include "sodium/utils.h" - -#ifndef SODIUM_LIBRARY_MINIMAL -# include "sodium/crypto_box_curve25519xchacha20poly1305.h" -# include "sodium/crypto_core_ed25519.h" -# include "sodium/crypto_core_ristretto255.h" -# include "sodium/crypto_scalarmult_ed25519.h" -# include "sodium/crypto_scalarmult_ristretto255.h" -# include "sodium/crypto_secretbox_xchacha20poly1305.h" -# include "sodium/crypto_pwhash_scryptsalsa208sha256.h" -# include "sodium/crypto_stream_salsa2012.h" -# include "sodium/crypto_stream_salsa208.h" -# include "sodium/crypto_stream_xchacha20.h" -#endif - -#endif diff --git a/win32/include/sodium/core.h b/win32/include/sodium/core.h deleted file mode 100644 index dd088d2cae..0000000000 --- a/win32/include/sodium/core.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifndef sodium_core_H -#define sodium_core_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -int sodium_init(void) - __attribute__ ((warn_unused_result)); - -/* ---- */ - -SODIUM_EXPORT -int sodium_set_misuse_handler(void (*handler)(void)); - -SODIUM_EXPORT -void sodium_misuse(void) - __attribute__ ((noreturn)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_aead_aes256gcm.h b/win32/include/sodium/crypto_aead_aes256gcm.h deleted file mode 100644 index 9baeb3f19f..0000000000 --- a/win32/include/sodium/crypto_aead_aes256gcm.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef crypto_aead_aes256gcm_H -#define crypto_aead_aes256gcm_H - -/* - * WARNING: Despite being the most popular AEAD construction due to its - * use in TLS, safely using AES-GCM in a different context is tricky. - * - * No more than ~ 350 GB of input data should be encrypted with a given key. - * This is for ~ 16 KB messages -- Actual figures vary according to - * message sizes. - * - * In addition, nonces are short and repeated nonces would totally destroy - * the security of this scheme. - * - * Nonces should thus come from atomic counters, which can be difficult to - * set up in a distributed environment. - * - * Unless you absolutely need AES-GCM, use crypto_aead_xchacha20poly1305_ietf_*() - * instead. It doesn't have any of these limitations. - * Or, if you don't need to authenticate additional data, just stick to - * crypto_secretbox(). - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -SODIUM_EXPORT -int crypto_aead_aes256gcm_is_available(void); - -#define crypto_aead_aes256gcm_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_keybytes(void); - -#define crypto_aead_aes256gcm_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_nsecbytes(void); - -#define crypto_aead_aes256gcm_NPUBBYTES 12U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_npubbytes(void); - -#define crypto_aead_aes256gcm_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_abytes(void); - -#define crypto_aead_aes256gcm_MESSAGEBYTES_MAX \ - SODIUM_MIN(SODIUM_SIZE_MAX - crypto_aead_aes256gcm_ABYTES, \ - (16ULL * ((1ULL << 32) - 2ULL))) -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_messagebytes_max(void); - -typedef struct CRYPTO_ALIGN(16) crypto_aead_aes256gcm_state_ { - unsigned char opaque[512]; -} crypto_aead_aes256gcm_state; - -SODIUM_EXPORT -size_t crypto_aead_aes256gcm_statebytes(void); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(4, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 9, 10))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((nonnull(1, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(4, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((nonnull(1, 2, 9, 10))); - -SODIUM_EXPORT -int crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const crypto_aead_aes256gcm_state *ctx_) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); - -SODIUM_EXPORT -void crypto_aead_aes256gcm_keygen(unsigned char k[crypto_aead_aes256gcm_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_aead_chacha20poly1305.h b/win32/include/sodium/crypto_aead_chacha20poly1305.h deleted file mode 100644 index 5d671df142..0000000000 --- a/win32/include/sodium/crypto_aead_chacha20poly1305.h +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef crypto_aead_chacha20poly1305_H -#define crypto_aead_chacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- IETF ChaCha20-Poly1305 construction with a 96-bit nonce and a 32-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_NPUBBYTES 12U - -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_abytes(void); - -#define crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX \ - SODIUM_MIN(SODIUM_SIZE_MAX - crypto_aead_chacha20poly1305_ietf_ABYTES, \ - (64ULL * ((1ULL << 32) - 1ULL))) -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_ietf_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(4, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 9, 10))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES]) - __attribute__ ((nonnull)); - -/* -- Original ChaCha20-Poly1305 construction with a 64-bit nonce and a 64-bit internal counter -- */ - -#define crypto_aead_chacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_keybytes(void); - -#define crypto_aead_chacha20poly1305_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_nsecbytes(void); - -#define crypto_aead_chacha20poly1305_NPUBBYTES 8U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_npubbytes(void); - -#define crypto_aead_chacha20poly1305_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_abytes(void); - -#define crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX \ - (SODIUM_SIZE_MAX - crypto_aead_chacha20poly1305_ABYTES) -SODIUM_EXPORT -size_t crypto_aead_chacha20poly1305_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(4, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 9, 10))); - -SODIUM_EXPORT -int crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); - -SODIUM_EXPORT -void crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -/* Aliases */ - -#define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_ietf_KEYBYTES -#define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_ietf_NSECBYTES -#define crypto_aead_chacha20poly1305_IETF_NPUBBYTES crypto_aead_chacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ietf_ABYTES -#define crypto_aead_chacha20poly1305_IETF_MESSAGEBYTES_MAX crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_aead_xchacha20poly1305.h b/win32/include/sodium/crypto_aead_xchacha20poly1305.h deleted file mode 100644 index 6643b0cbf5..0000000000 --- a/win32/include/sodium/crypto_aead_xchacha20poly1305.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef crypto_aead_xchacha20poly1305_H -#define crypto_aead_xchacha20poly1305_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_keybytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NSECBYTES 0U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_npubbytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_abytes(void); - -#define crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX \ - (SODIUM_SIZE_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES) -SODIUM_EXPORT -size_t crypto_aead_xchacha20poly1305_ietf_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, - unsigned long long *clen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, - unsigned long long *mlen_p, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(4, 8, 9))); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, - unsigned char *mac, - unsigned long long *maclen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *nsec, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 9, 10))); - -SODIUM_EXPORT -int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, - unsigned char *nsec, - const unsigned char *c, - unsigned long long clen, - const unsigned char *mac, - const unsigned char *ad, - unsigned long long adlen, - const unsigned char *npub, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5, 8, 9))); - -SODIUM_EXPORT -void crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]) - __attribute__ ((nonnull)); - -/* Aliases */ - -#define crypto_aead_xchacha20poly1305_IETF_KEYBYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES -#define crypto_aead_xchacha20poly1305_IETF_NSECBYTES crypto_aead_xchacha20poly1305_ietf_NSECBYTES -#define crypto_aead_xchacha20poly1305_IETF_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES -#define crypto_aead_xchacha20poly1305_IETF_ABYTES crypto_aead_xchacha20poly1305_ietf_ABYTES -#define crypto_aead_xchacha20poly1305_IETF_MESSAGEBYTES_MAX crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_auth.h b/win32/include/sodium/crypto_auth.h deleted file mode 100644 index 540aee0e8d..0000000000 --- a/win32/include/sodium/crypto_auth.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_auth_H -#define crypto_auth_H - -#include - -#include "crypto_auth_hmacsha512256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES -SODIUM_EXPORT -size_t crypto_auth_bytes(void); - -#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES -SODIUM_EXPORT -size_t crypto_auth_keybytes(void); - -#define crypto_auth_PRIMITIVE "hmacsha512256" -SODIUM_EXPORT -const char *crypto_auth_primitive(void); - -SODIUM_EXPORT -int crypto_auth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_auth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -void crypto_auth_keygen(unsigned char k[crypto_auth_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_auth_hmacsha256.h b/win32/include/sodium/crypto_auth_hmacsha256.h deleted file mode 100644 index 3da864c7d2..0000000000 --- a/win32/include/sodium/crypto_auth_hmacsha256.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef crypto_auth_hmacsha256_H -#define crypto_auth_hmacsha256_H - -#include -#include "crypto_hash_sha256.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_bytes(void); - -#define crypto_auth_hmacsha256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha256_state { - crypto_hash_sha256_state ictx; - crypto_hash_sha256_state octx; -} crypto_auth_hmacsha256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_init(crypto_auth_hmacsha256_state *state, - const unsigned char *key, - size_t keylen) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_update(crypto_auth_hmacsha256_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_auth_hmacsha256_final(crypto_auth_hmacsha256_state *state, - unsigned char *out) __attribute__ ((nonnull)); - - -SODIUM_EXPORT -void crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_auth_hmacsha512.h b/win32/include/sodium/crypto_auth_hmacsha512.h deleted file mode 100644 index d992cb8163..0000000000 --- a/win32/include/sodium/crypto_auth_hmacsha512.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef crypto_auth_hmacsha512_H -#define crypto_auth_hmacsha512_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_bytes(void); - -#define crypto_auth_hmacsha512_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -/* ------------------------------------------------------------------------- */ - -typedef struct crypto_auth_hmacsha512_state { - crypto_hash_sha512_state ictx; - crypto_hash_sha512_state octx; -} crypto_auth_hmacsha512_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_init(crypto_auth_hmacsha512_state *state, - const unsigned char *key, - size_t keylen) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_update(crypto_auth_hmacsha512_state *state, - const unsigned char *in, - unsigned long long inlen) __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_auth_hmacsha512_final(crypto_auth_hmacsha512_state *state, - unsigned char *out) __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_auth_hmacsha512256.h b/win32/include/sodium/crypto_auth_hmacsha512256.h deleted file mode 100644 index 3fb5263892..0000000000 --- a/win32/include/sodium/crypto_auth_hmacsha512256.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef crypto_auth_hmacsha512256_H -#define crypto_auth_hmacsha512256_H - -#include -#include "crypto_auth_hmacsha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_auth_hmacsha512256_BYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_bytes(void); - -#define crypto_auth_hmacsha512256_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_keybytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -/* ------------------------------------------------------------------------- */ - -typedef crypto_auth_hmacsha512_state crypto_auth_hmacsha512256_state; - -SODIUM_EXPORT -size_t crypto_auth_hmacsha512256_statebytes(void); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_init(crypto_auth_hmacsha512256_state *state, - const unsigned char *key, - size_t keylen) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_update(crypto_auth_hmacsha512256_state *state, - const unsigned char *in, - unsigned long long inlen) __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_auth_hmacsha512256_final(crypto_auth_hmacsha512256_state *state, - unsigned char *out) __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_auth_hmacsha512256_keygen(unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_box.h b/win32/include/sodium/crypto_box.h deleted file mode 100644 index e060dd29fc..0000000000 --- a/win32/include/sodium/crypto_box.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef crypto_box_H -#define crypto_box_H - -/* - * THREAD SAFETY: crypto_box_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions are always thread-safe. - */ - -#include - -#include "crypto_box_curve25519xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_SEEDBYTES crypto_box_curve25519xsalsa20poly1305_SEEDBYTES -SODIUM_EXPORT -size_t crypto_box_seedbytes(void); - -#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_box_publickeybytes(void); - -#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_box_secretkeybytes(void); - -#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_box_noncebytes(void); - -#define crypto_box_MACBYTES crypto_box_curve25519xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_box_macbytes(void); - -#define crypto_box_MESSAGEBYTES_MAX crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX -SODIUM_EXPORT -size_t crypto_box_messagebytes_max(void); - -#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_box_primitive(void); - -SODIUM_EXPORT -int crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_keypair(unsigned char *pk, unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 2, 5, 6, 7))); - -SODIUM_EXPORT -int crypto_box_open_detached(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6, 7))); - -/* -- Precomputation interface -- */ - -#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES -SODIUM_EXPORT -size_t crypto_box_beforenmbytes(void); - -SODIUM_EXPORT -int crypto_box_beforenm(unsigned char *k, const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -SODIUM_EXPORT -int crypto_box_detached_afternm(unsigned char *c, unsigned char *mac, - const unsigned char *m, unsigned long long mlen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull(1, 2, 5, 6))); - -SODIUM_EXPORT -int crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6))); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_SEALBYTES (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_seal(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *pk) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_box_seal_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_box_zerobytes(void); - -#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_box_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_box(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *pk, const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_afternm(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_box_open_afternm(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_box_curve25519xchacha20poly1305.h b/win32/include/sodium/crypto_box_curve25519xchacha20poly1305.h deleted file mode 100644 index 26a3d31efa..0000000000 --- a/win32/include/sodium/crypto_box_curve25519xchacha20poly1305.h +++ /dev/null @@ -1,164 +0,0 @@ - -#ifndef crypto_box_curve25519xchacha20poly1305_H -#define crypto_box_curve25519xchacha20poly1305_H - -#include -#include "crypto_stream_xchacha20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xchacha20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_seedbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_noncebytes(void); - -#define crypto_box_curve25519xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_macbytes(void); - -#define crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX \ - (crypto_stream_xchacha20_MESSAGEBYTES_MAX - crypto_box_curve25519xchacha20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_keypair(unsigned char *pk, - unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 2, 5, 6, 7))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6, 7))); - -/* -- Precomputation interface -- */ - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_easy_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_easy_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_detached_afternm(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 5, 6))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_open_detached_afternm(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6))); - -/* -- Ephemeral SK interface -- */ - -#define crypto_box_curve25519xchacha20poly1305_SEALBYTES \ - (crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES + \ - crypto_box_curve25519xchacha20poly1305_MACBYTES) - -SODIUM_EXPORT -size_t crypto_box_curve25519xchacha20poly1305_sealbytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_box_curve25519xchacha20poly1305_seal_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_box_curve25519xsalsa20poly1305.h b/win32/include/sodium/crypto_box_curve25519xsalsa20poly1305.h deleted file mode 100644 index e733f49995..0000000000 --- a/win32/include/sodium/crypto_box_curve25519xsalsa20poly1305.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef crypto_box_curve25519xsalsa20poly1305_H -#define crypto_box_curve25519xsalsa20poly1305_H - -#include -#include "crypto_stream_xsalsa20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_box_curve25519xsalsa20poly1305_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_seedbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_publickeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_secretkeybytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES 32U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_beforenmbytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_noncebytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_macbytes(void); - -/* Only for the libsodium API - The NaCl compatibility API would require BOXZEROBYTES extra bytes */ -#define crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX \ - (crypto_stream_xsalsa20_MESSAGEBYTES_MAX - crypto_box_curve25519xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_seed_keypair(unsigned char *pk, - unsigned char *sk, - const unsigned char *seed) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_keypair(unsigned char *pk, - unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_beforenm(unsigned char *k, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_boxzerobytes(void); - -#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES \ - (crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES + \ - crypto_box_curve25519xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_box_curve25519xsalsa20poly1305_zerobytes(void); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *pk, - const unsigned char *sk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5, 6))); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_afternm(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_box_curve25519xsalsa20poly1305_open_afternm(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_ed25519.h b/win32/include/sodium/crypto_core_ed25519.h deleted file mode 100644 index 3eae00c456..0000000000 --- a/win32/include/sodium/crypto_core_ed25519.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef crypto_core_ed25519_H -#define crypto_core_ed25519_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_ed25519_BYTES 32 -SODIUM_EXPORT -size_t crypto_core_ed25519_bytes(void); - -#define crypto_core_ed25519_UNIFORMBYTES 32 -SODIUM_EXPORT -size_t crypto_core_ed25519_uniformbytes(void); - -#define crypto_core_ed25519_HASHBYTES 64 -SODIUM_EXPORT -size_t crypto_core_ed25519_hashbytes(void); - -#define crypto_core_ed25519_SCALARBYTES 32 -SODIUM_EXPORT -size_t crypto_core_ed25519_scalarbytes(void); - -#define crypto_core_ed25519_NONREDUCEDSCALARBYTES 64 -SODIUM_EXPORT -size_t crypto_core_ed25519_nonreducedscalarbytes(void); - -SODIUM_EXPORT -int crypto_core_ed25519_is_valid_point(const unsigned char *p) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ed25519_add(unsigned char *r, - const unsigned char *p, const unsigned char *q) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ed25519_sub(unsigned char *r, - const unsigned char *p, const unsigned char *q) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ed25519_from_uniform(unsigned char *p, const unsigned char *r) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ed25519_from_hash(unsigned char *p, const unsigned char *h) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_random(unsigned char *p) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_random(unsigned char *r) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ed25519_scalar_invert(unsigned char *recip, const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_negate(unsigned char *neg, const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_complement(unsigned char *comp, const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_add(unsigned char *z, const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_sub(unsigned char *z, const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ed25519_scalar_mul(unsigned char *z, const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -/* - * The interval `s` is sampled from should be at least 317 bits to ensure almost - * uniformity of `r` over `L`. - */ -SODIUM_EXPORT -void crypto_core_ed25519_scalar_reduce(unsigned char *r, const unsigned char *s) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_hchacha20.h b/win32/include/sodium/crypto_core_hchacha20.h deleted file mode 100644 index ece141b09b..0000000000 --- a/win32/include/sodium/crypto_core_hchacha20.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef crypto_core_hchacha20_H -#define crypto_core_hchacha20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hchacha20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_outputbytes(void); - -#define crypto_core_hchacha20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_inputbytes(void); - -#define crypto_core_hchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hchacha20_keybytes(void); - -#define crypto_core_hchacha20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hchacha20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hchacha20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c) - __attribute__ ((nonnull(1, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_hsalsa20.h b/win32/include/sodium/crypto_core_hsalsa20.h deleted file mode 100644 index 4bf7a48786..0000000000 --- a/win32/include/sodium/crypto_core_hsalsa20.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef crypto_core_hsalsa20_H -#define crypto_core_hsalsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_hsalsa20_OUTPUTBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_outputbytes(void); - -#define crypto_core_hsalsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_inputbytes(void); - -#define crypto_core_hsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_keybytes(void); - -#define crypto_core_hsalsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_hsalsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_hsalsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c) - __attribute__ ((nonnull(1, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_ristretto255.h b/win32/include/sodium/crypto_core_ristretto255.h deleted file mode 100644 index f2820e5576..0000000000 --- a/win32/include/sodium/crypto_core_ristretto255.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef crypto_core_ristretto255_H -#define crypto_core_ristretto255_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_ristretto255_BYTES 32 -SODIUM_EXPORT -size_t crypto_core_ristretto255_bytes(void); - -#define crypto_core_ristretto255_HASHBYTES 64 -SODIUM_EXPORT -size_t crypto_core_ristretto255_hashbytes(void); - -#define crypto_core_ristretto255_SCALARBYTES 32 -SODIUM_EXPORT -size_t crypto_core_ristretto255_scalarbytes(void); - -#define crypto_core_ristretto255_NONREDUCEDSCALARBYTES 64 -SODIUM_EXPORT -size_t crypto_core_ristretto255_nonreducedscalarbytes(void); - -SODIUM_EXPORT -int crypto_core_ristretto255_is_valid_point(const unsigned char *p) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ristretto255_add(unsigned char *r, - const unsigned char *p, const unsigned char *q) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ristretto255_sub(unsigned char *r, - const unsigned char *p, const unsigned char *q) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ristretto255_from_hash(unsigned char *p, - const unsigned char *r) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_random(unsigned char *p) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_random(unsigned char *r) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_core_ristretto255_scalar_invert(unsigned char *recip, - const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_negate(unsigned char *neg, - const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_complement(unsigned char *comp, - const unsigned char *s) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_add(unsigned char *z, - const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_sub(unsigned char *z, - const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_mul(unsigned char *z, - const unsigned char *x, - const unsigned char *y) - __attribute__ ((nonnull)); - -/* - * The interval `s` is sampled from should be at least 317 bits to ensure almost - * uniformity of `r` over `L`. - */ -SODIUM_EXPORT -void crypto_core_ristretto255_scalar_reduce(unsigned char *r, - const unsigned char *s) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_salsa20.h b/win32/include/sodium/crypto_core_salsa20.h deleted file mode 100644 index bd79fd9f54..0000000000 --- a/win32/include/sodium/crypto_core_salsa20.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef crypto_core_salsa20_H -#define crypto_core_salsa20_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa20_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa20_outputbytes(void); - -#define crypto_core_salsa20_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_inputbytes(void); - -#define crypto_core_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa20_keybytes(void); - -#define crypto_core_salsa20_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa20_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa20(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c) - __attribute__ ((nonnull(1, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_salsa2012.h b/win32/include/sodium/crypto_core_salsa2012.h deleted file mode 100644 index 05957591ca..0000000000 --- a/win32/include/sodium/crypto_core_salsa2012.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef crypto_core_salsa2012_H -#define crypto_core_salsa2012_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa2012_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa2012_outputbytes(void); - -#define crypto_core_salsa2012_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_inputbytes(void); - -#define crypto_core_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa2012_keybytes(void); - -#define crypto_core_salsa2012_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa2012_constbytes(void); - -SODIUM_EXPORT -int crypto_core_salsa2012(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c) - __attribute__ ((nonnull(1, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_core_salsa208.h b/win32/include/sodium/crypto_core_salsa208.h deleted file mode 100644 index d2f216af26..0000000000 --- a/win32/include/sodium/crypto_core_salsa208.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef crypto_core_salsa208_H -#define crypto_core_salsa208_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_core_salsa208_OUTPUTBYTES 64U -SODIUM_EXPORT -size_t crypto_core_salsa208_outputbytes(void) - __attribute__ ((deprecated)); - -#define crypto_core_salsa208_INPUTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_inputbytes(void) - __attribute__ ((deprecated)); - -#define crypto_core_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_core_salsa208_keybytes(void) - __attribute__ ((deprecated)); - -#define crypto_core_salsa208_CONSTBYTES 16U -SODIUM_EXPORT -size_t crypto_core_salsa208_constbytes(void) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_core_salsa208(unsigned char *out, const unsigned char *in, - const unsigned char *k, const unsigned char *c) - __attribute__ ((nonnull(1, 2, 3))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_generichash.h b/win32/include/sodium/crypto_generichash.h deleted file mode 100644 index d897e5d26c..0000000000 --- a/win32/include/sodium/crypto_generichash.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef crypto_generichash_H -#define crypto_generichash_H - -#include - -#include "crypto_generichash_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_generichash_BYTES_MIN crypto_generichash_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_bytes_min(void); - -#define crypto_generichash_BYTES_MAX crypto_generichash_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_bytes_max(void); - -#define crypto_generichash_BYTES crypto_generichash_blake2b_BYTES -SODIUM_EXPORT -size_t crypto_generichash_bytes(void); - -#define crypto_generichash_KEYBYTES_MIN crypto_generichash_blake2b_KEYBYTES_MIN -SODIUM_EXPORT -size_t crypto_generichash_keybytes_min(void); - -#define crypto_generichash_KEYBYTES_MAX crypto_generichash_blake2b_KEYBYTES_MAX -SODIUM_EXPORT -size_t crypto_generichash_keybytes_max(void); - -#define crypto_generichash_KEYBYTES crypto_generichash_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_generichash_keybytes(void); - -#define crypto_generichash_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_generichash_primitive(void); - -/* - * Important when writing bindings for other programming languages: - * the state address should be 64-bytes aligned. - */ -typedef crypto_generichash_blake2b_state crypto_generichash_state; - -SODIUM_EXPORT -size_t crypto_generichash_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash(unsigned char *out, size_t outlen, - const unsigned char *in, unsigned long long inlen, - const unsigned char *key, size_t keylen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_init(crypto_generichash_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_update(crypto_generichash_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_final(crypto_generichash_state *state, - unsigned char *out, const size_t outlen) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_generichash_blake2b.h b/win32/include/sodium/crypto_generichash_blake2b.h deleted file mode 100644 index fee9d8ad19..0000000000 --- a/win32/include/sodium/crypto_generichash_blake2b.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef crypto_generichash_blake2b_H -#define crypto_generichash_blake2b_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack(1) -#else -# pragma pack(push, 1) -#endif - -typedef struct CRYPTO_ALIGN(64) crypto_generichash_blake2b_state { - unsigned char opaque[384]; -} crypto_generichash_blake2b_state; - -#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack() -#else -# pragma pack(pop) -#endif - -#define crypto_generichash_blake2b_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_min(void); - -#define crypto_generichash_blake2b_BYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes_max(void); - -#define crypto_generichash_blake2b_BYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_bytes(void); - -#define crypto_generichash_blake2b_KEYBYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_min(void); - -#define crypto_generichash_blake2b_KEYBYTES_MAX 64U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes_max(void); - -#define crypto_generichash_blake2b_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_keybytes(void); - -#define crypto_generichash_blake2b_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_saltbytes(void); - -#define crypto_generichash_blake2b_PERSONALBYTES 16U -SODIUM_EXPORT -size_t crypto_generichash_blake2b_personalbytes(void); - -SODIUM_EXPORT -size_t crypto_generichash_blake2b_statebytes(void); - -SODIUM_EXPORT -int crypto_generichash_blake2b(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, size_t keylen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_blake2b_salt_personal(unsigned char *out, size_t outlen, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *key, - size_t keylen, - const unsigned char *salt, - const unsigned char *personal) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_blake2b_init_salt_personal(crypto_generichash_blake2b_state *state, - const unsigned char *key, - const size_t keylen, const size_t outlen, - const unsigned char *salt, - const unsigned char *personal) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, - unsigned char *out, - const size_t outlen) __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_generichash_blake2b_keygen(unsigned char k[crypto_generichash_blake2b_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_hash.h b/win32/include/sodium/crypto_hash.h deleted file mode 100644 index 8752f9cafe..0000000000 --- a/win32/include/sodium/crypto_hash.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef crypto_hash_H -#define crypto_hash_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include - -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_hash_BYTES crypto_hash_sha512_BYTES -SODIUM_EXPORT -size_t crypto_hash_bytes(void); - -SODIUM_EXPORT -int crypto_hash(unsigned char *out, const unsigned char *in, - unsigned long long inlen) __attribute__ ((nonnull(1))); - -#define crypto_hash_PRIMITIVE "sha512" -SODIUM_EXPORT -const char *crypto_hash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_hash_sha256.h b/win32/include/sodium/crypto_hash_sha256.h deleted file mode 100644 index b18217e18d..0000000000 --- a/win32/include/sodium/crypto_hash_sha256.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef crypto_hash_sha256_H -#define crypto_hash_sha256_H - -/* - * WARNING: Unless you absolutely need to use SHA256 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA256, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha256_state { - uint32_t state[8]; - uint64_t count; - uint8_t buf[64]; -} crypto_hash_sha256_state; - -SODIUM_EXPORT -size_t crypto_hash_sha256_statebytes(void); - -#define crypto_hash_sha256_BYTES 32U -SODIUM_EXPORT -size_t crypto_hash_sha256_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha256(unsigned char *out, const unsigned char *in, - unsigned long long inlen) __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_hash_sha256_init(crypto_hash_sha256_state *state) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_hash_sha256_update(crypto_hash_sha256_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_hash_sha256_final(crypto_hash_sha256_state *state, - unsigned char *out) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_hash_sha512.h b/win32/include/sodium/crypto_hash_sha512.h deleted file mode 100644 index 8efa7193ad..0000000000 --- a/win32/include/sodium/crypto_hash_sha512.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef crypto_hash_sha512_H -#define crypto_hash_sha512_H - -/* - * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, - * purposes, you might want to consider crypto_generichash() instead. - * Unlike SHA512, crypto_generichash() is not vulnerable to length - * extension attacks. - */ - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_hash_sha512_state { - uint64_t state[8]; - uint64_t count[2]; - uint8_t buf[128]; -} crypto_hash_sha512_state; - -SODIUM_EXPORT -size_t crypto_hash_sha512_statebytes(void); - -#define crypto_hash_sha512_BYTES 64U -SODIUM_EXPORT -size_t crypto_hash_sha512_bytes(void); - -SODIUM_EXPORT -int crypto_hash_sha512(unsigned char *out, const unsigned char *in, - unsigned long long inlen) __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_hash_sha512_init(crypto_hash_sha512_state *state) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_hash_sha512_update(crypto_hash_sha512_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_hash_sha512_final(crypto_hash_sha512_state *state, - unsigned char *out) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_kdf.h b/win32/include/sodium/crypto_kdf.h deleted file mode 100644 index ac2fc6183c..0000000000 --- a/win32/include/sodium/crypto_kdf.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_kdf_H -#define crypto_kdf_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_BYTES_MIN crypto_kdf_blake2b_BYTES_MIN -SODIUM_EXPORT -size_t crypto_kdf_bytes_min(void); - -#define crypto_kdf_BYTES_MAX crypto_kdf_blake2b_BYTES_MAX -SODIUM_EXPORT -size_t crypto_kdf_bytes_max(void); - -#define crypto_kdf_CONTEXTBYTES crypto_kdf_blake2b_CONTEXTBYTES -SODIUM_EXPORT -size_t crypto_kdf_contextbytes(void); - -#define crypto_kdf_KEYBYTES crypto_kdf_blake2b_KEYBYTES -SODIUM_EXPORT -size_t crypto_kdf_keybytes(void); - -#define crypto_kdf_PRIMITIVE "blake2b" -SODIUM_EXPORT -const char *crypto_kdf_primitive(void) - __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_CONTEXTBYTES], - const unsigned char key[crypto_kdf_KEYBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_kdf_blake2b.h b/win32/include/sodium/crypto_kdf_blake2b.h deleted file mode 100644 index 3ae47dd32c..0000000000 --- a/win32/include/sodium/crypto_kdf_blake2b.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef crypto_kdf_blake2b_H -#define crypto_kdf_blake2b_H - -#include -#include - -#include "crypto_kdf_blake2b.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kdf_blake2b_BYTES_MIN 16 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_min(void); - -#define crypto_kdf_blake2b_BYTES_MAX 64 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_bytes_max(void); - -#define crypto_kdf_blake2b_CONTEXTBYTES 8 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_contextbytes(void); - -#define crypto_kdf_blake2b_KEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kdf_blake2b_keybytes(void); - -SODIUM_EXPORT -int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len, - uint64_t subkey_id, - const char ctx[crypto_kdf_blake2b_CONTEXTBYTES], - const unsigned char key[crypto_kdf_blake2b_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_kx.h b/win32/include/sodium/crypto_kx.h deleted file mode 100644 index 347132c320..0000000000 --- a/win32/include/sodium/crypto_kx.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef crypto_kx_H -#define crypto_kx_H - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_kx_PUBLICKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_publickeybytes(void); - -#define crypto_kx_SECRETKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_secretkeybytes(void); - -#define crypto_kx_SEEDBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_seedbytes(void); - -#define crypto_kx_SESSIONKEYBYTES 32 -SODIUM_EXPORT -size_t crypto_kx_sessionkeybytes(void); - -#define crypto_kx_PRIMITIVE "x25519blake2b" -SODIUM_EXPORT -const char *crypto_kx_primitive(void); - -SODIUM_EXPORT -int crypto_kx_seed_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES], - const unsigned char seed[crypto_kx_SEEDBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], - unsigned char sk[crypto_kx_SECRETKEYBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char client_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 4, 5))); - -SODIUM_EXPORT -int crypto_kx_server_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], - unsigned char tx[crypto_kx_SESSIONKEYBYTES], - const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES], - const unsigned char server_sk[crypto_kx_SECRETKEYBYTES], - const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES]) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 4, 5))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_onetimeauth.h b/win32/include/sodium/crypto_onetimeauth.h deleted file mode 100644 index 7cd7b07060..0000000000 --- a/win32/include/sodium/crypto_onetimeauth.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef crypto_onetimeauth_H -#define crypto_onetimeauth_H - -#include - -#include "crypto_onetimeauth_poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_onetimeauth_poly1305_state crypto_onetimeauth_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_statebytes(void); - -#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_bytes(void); - -#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_onetimeauth_keybytes(void); - -#define crypto_onetimeauth_PRIMITIVE "poly1305" -SODIUM_EXPORT -const char *crypto_onetimeauth_primitive(void); - -SODIUM_EXPORT -int crypto_onetimeauth(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_onetimeauth_init(crypto_onetimeauth_state *state, - const unsigned char *key) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_onetimeauth_update(crypto_onetimeauth_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_onetimeauth_final(crypto_onetimeauth_state *state, - unsigned char *out) __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_onetimeauth_keygen(unsigned char k[crypto_onetimeauth_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_onetimeauth_poly1305.h b/win32/include/sodium/crypto_onetimeauth_poly1305.h deleted file mode 100644 index f3e34d86df..0000000000 --- a/win32/include/sodium/crypto_onetimeauth_poly1305.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef crypto_onetimeauth_poly1305_H -#define crypto_onetimeauth_poly1305_H - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#include -#include -#include - -#include - -#include "export.h" - -typedef struct CRYPTO_ALIGN(16) crypto_onetimeauth_poly1305_state { - unsigned char opaque[256]; -} crypto_onetimeauth_poly1305_state; - -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_statebytes(void); - -#define crypto_onetimeauth_poly1305_BYTES 16U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_bytes(void); - -#define crypto_onetimeauth_poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_onetimeauth_poly1305_keybytes(void); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305(unsigned char *out, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_verify(const unsigned char *h, - const unsigned char *in, - unsigned long long inlen, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, - const unsigned char *key) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, - const unsigned char *in, - unsigned long long inlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, - unsigned char *out) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_onetimeauth_poly1305_keygen(unsigned char k[crypto_onetimeauth_poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_pwhash.h b/win32/include/sodium/crypto_pwhash.h deleted file mode 100644 index 585a993efd..0000000000 --- a/win32/include/sodium/crypto_pwhash.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef crypto_pwhash_H -#define crypto_pwhash_H - -#include - -#include "crypto_pwhash_argon2i.h" -#include "crypto_pwhash_argon2id.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_ALG_ARGON2I13 crypto_pwhash_argon2i_ALG_ARGON2I13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2i13(void); - -#define crypto_pwhash_ALG_ARGON2ID13 crypto_pwhash_argon2id_ALG_ARGON2ID13 -SODIUM_EXPORT -int crypto_pwhash_alg_argon2id13(void); - -#define crypto_pwhash_ALG_DEFAULT crypto_pwhash_ALG_ARGON2ID13 -SODIUM_EXPORT -int crypto_pwhash_alg_default(void); - -#define crypto_pwhash_BYTES_MIN crypto_pwhash_argon2id_BYTES_MIN -SODIUM_EXPORT -size_t crypto_pwhash_bytes_min(void); - -#define crypto_pwhash_BYTES_MAX crypto_pwhash_argon2id_BYTES_MAX -SODIUM_EXPORT -size_t crypto_pwhash_bytes_max(void); - -#define crypto_pwhash_PASSWD_MIN crypto_pwhash_argon2id_PASSWD_MIN -SODIUM_EXPORT -size_t crypto_pwhash_passwd_min(void); - -#define crypto_pwhash_PASSWD_MAX crypto_pwhash_argon2id_PASSWD_MAX -SODIUM_EXPORT -size_t crypto_pwhash_passwd_max(void); - -#define crypto_pwhash_SALTBYTES crypto_pwhash_argon2id_SALTBYTES -SODIUM_EXPORT -size_t crypto_pwhash_saltbytes(void); - -#define crypto_pwhash_STRBYTES crypto_pwhash_argon2id_STRBYTES -SODIUM_EXPORT -size_t crypto_pwhash_strbytes(void); - -#define crypto_pwhash_STRPREFIX crypto_pwhash_argon2id_STRPREFIX -SODIUM_EXPORT -const char *crypto_pwhash_strprefix(void); - -#define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_argon2id_OPSLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_min(void); - -#define crypto_pwhash_OPSLIMIT_MAX crypto_pwhash_argon2id_OPSLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_max(void); - -#define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_argon2id_MEMLIMIT_MIN -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_min(void); - -#define crypto_pwhash_MEMLIMIT_MAX crypto_pwhash_argon2id_MEMLIMIT_MAX -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_max(void); - -#define crypto_pwhash_OPSLIMIT_INTERACTIVE crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_interactive(void); - -#define crypto_pwhash_MEMLIMIT_INTERACTIVE crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_interactive(void); - -#define crypto_pwhash_OPSLIMIT_MODERATE crypto_pwhash_argon2id_OPSLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_moderate(void); - -#define crypto_pwhash_MEMLIMIT_MODERATE crypto_pwhash_argon2id_MEMLIMIT_MODERATE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_moderate(void); - -#define crypto_pwhash_OPSLIMIT_SENSITIVE crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_opslimit_sensitive(void); - -#define crypto_pwhash_MEMLIMIT_SENSITIVE crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE -SODIUM_EXPORT -size_t crypto_pwhash_memlimit_sensitive(void); - -/* - * With this function, do not forget to store all parameters, including the - * algorithm identifier in order to produce deterministic output. - * The crypto_pwhash_* definitions, including crypto_pwhash_ALG_DEFAULT, - * may change. - */ -SODIUM_EXPORT -int crypto_pwhash(unsigned char * const out, unsigned long long outlen, - const char * const passwd, unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, int alg) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -/* - * The output string already includes all the required parameters, including - * the algorithm identifier. The string is all that has to be stored in - * order to verify a password. - */ -SODIUM_EXPORT -int crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], - const char * const passwd, unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_str_alg(char out[crypto_pwhash_STRBYTES], - const char * const passwd, unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit, int alg) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_str_needs_rehash(const char str[crypto_pwhash_STRBYTES], - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#define crypto_pwhash_PRIMITIVE "argon2i" -SODIUM_EXPORT -const char *crypto_pwhash_primitive(void) - __attribute__ ((warn_unused_result)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_pwhash_argon2i.h b/win32/include/sodium/crypto_pwhash_argon2i.h deleted file mode 100644 index 88ff6221d6..0000000000 --- a/win32/include/sodium/crypto_pwhash_argon2i.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef crypto_pwhash_argon2i_H -#define crypto_pwhash_argon2i_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2i_ALG_ARGON2I13 1 -SODIUM_EXPORT -int crypto_pwhash_argon2i_alg_argon2i13(void); - -#define crypto_pwhash_argon2i_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_min(void); - -#define crypto_pwhash_argon2i_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 4294967295U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_bytes_max(void); - -#define crypto_pwhash_argon2i_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_min(void); - -#define crypto_pwhash_argon2i_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_passwd_max(void); - -#define crypto_pwhash_argon2i_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_saltbytes(void); - -#define crypto_pwhash_argon2i_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_strbytes(void); - -#define crypto_pwhash_argon2i_STRPREFIX "$argon2i$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2i_strprefix(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MIN 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_min(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_max(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_min(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MAX \ - ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_max(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_interactive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_interactive(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_MODERATE 6U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_moderate(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_MODERATE 134217728U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_moderate(void); - -#define crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE 8U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_opslimit_sensitive(void); - -#define crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE 536870912U -SODIUM_EXPORT -size_t crypto_pwhash_argon2i_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2i(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES], - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_pwhash_argon2id.h b/win32/include/sodium/crypto_pwhash_argon2id.h deleted file mode 100644 index 7183abd186..0000000000 --- a/win32/include/sodium/crypto_pwhash_argon2id.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef crypto_pwhash_argon2id_H -#define crypto_pwhash_argon2id_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_argon2id_ALG_ARGON2ID13 2 -SODIUM_EXPORT -int crypto_pwhash_argon2id_alg_argon2id13(void); - -#define crypto_pwhash_argon2id_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_min(void); - -#define crypto_pwhash_argon2id_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 4294967295U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_bytes_max(void); - -#define crypto_pwhash_argon2id_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_min(void); - -#define crypto_pwhash_argon2id_PASSWD_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_passwd_max(void); - -#define crypto_pwhash_argon2id_SALTBYTES 16U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_saltbytes(void); - -#define crypto_pwhash_argon2id_STRBYTES 128U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_strbytes(void); - -#define crypto_pwhash_argon2id_STRPREFIX "$argon2id$" -SODIUM_EXPORT -const char *crypto_pwhash_argon2id_strprefix(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MIN 1U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_min(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_max(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MIN 8192U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_min(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MAX \ - ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_max(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE 2U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_interactive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE 67108864U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_interactive(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_MODERATE 3U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_moderate(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_MODERATE 268435456U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_moderate(void); - -#define crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE 4U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_opslimit_sensitive(void); - -#define crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_argon2id_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_argon2id(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, size_t memlimit, - int alg) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES], - unsigned long long opslimit, size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_pwhash_scryptsalsa208sha256.h b/win32/include/sodium/crypto_pwhash_scryptsalsa208sha256.h deleted file mode 100644 index 5c0bf7d390..0000000000 --- a/win32/include/sodium/crypto_pwhash_scryptsalsa208sha256.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef crypto_pwhash_scryptsalsa208sha256_H -#define crypto_pwhash_scryptsalsa208sha256_H - -#include -#include -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MIN 16U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_BYTES_MAX \ - SODIUM_MIN(SODIUM_SIZE_MAX, 0x1fffffffe0ULL) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_bytes_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN 0U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_passwd_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); - -#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" -SODIUM_EXPORT -const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 32768U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX 4294967295U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_min(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX \ - SODIUM_MIN(SIZE_MAX, 68719476736ULL) -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_max(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); - -#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); - -#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824U -SODIUM_EXPORT -size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, - unsigned long long outlen, - const char * const passwd, - unsigned long long passwdlen, - const unsigned char * const salt, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen, - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - const char * const passwd, - unsigned long long passwdlen) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, - const uint8_t * salt, size_t saltlen, - uint64_t N, uint32_t r, uint32_t p, - uint8_t * buf, size_t buflen) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], - unsigned long long opslimit, - size_t memlimit) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_scalarmult.h b/win32/include/sodium/crypto_scalarmult.h deleted file mode 100644 index 1c68585378..0000000000 --- a/win32/include/sodium/crypto_scalarmult.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef crypto_scalarmult_H -#define crypto_scalarmult_H - -#include - -#include "crypto_scalarmult_curve25519.h" -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES -SODIUM_EXPORT -size_t crypto_scalarmult_bytes(void); - -#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES -SODIUM_EXPORT -size_t crypto_scalarmult_scalarbytes(void); - -#define crypto_scalarmult_PRIMITIVE "curve25519" -SODIUM_EXPORT -const char *crypto_scalarmult_primitive(void); - -SODIUM_EXPORT -int crypto_scalarmult_base(unsigned char *q, const unsigned char *n) - __attribute__ ((nonnull)); - -/* - * NOTE: Do not use the result of this function directly for key exchange. - * - * Hash the result with the public keys in order to compute a shared - * secret key: H(q || client_pk || server_pk) - * - * Or unless this is not an option, use the crypto_kx() API instead. - */ -SODIUM_EXPORT -int crypto_scalarmult(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_scalarmult_curve25519.h b/win32/include/sodium/crypto_scalarmult_curve25519.h deleted file mode 100644 index 60e9d0c5a4..0000000000 --- a/win32/include/sodium/crypto_scalarmult_curve25519.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef crypto_scalarmult_curve25519_H -#define crypto_scalarmult_curve25519_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_curve25519_BYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_bytes(void); - -#define crypto_scalarmult_curve25519_SCALARBYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_curve25519_scalarbytes(void); - -/* - * NOTE: Do not use the result of this function directly for key exchange. - * - * Hash the result with the public keys in order to compute a shared - * secret key: H(q || client_pk || server_pk) - * - * Or unless this is not an option, use the crypto_kx() API instead. - */ -SODIUM_EXPORT -int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_scalarmult_curve25519_base(unsigned char *q, - const unsigned char *n) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_scalarmult_ed25519.h b/win32/include/sodium/crypto_scalarmult_ed25519.h deleted file mode 100644 index 2dfa4d7073..0000000000 --- a/win32/include/sodium/crypto_scalarmult_ed25519.h +++ /dev/null @@ -1,51 +0,0 @@ - -#ifndef crypto_scalarmult_ed25519_H -#define crypto_scalarmult_ed25519_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_ed25519_BYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_ed25519_bytes(void); - -#define crypto_scalarmult_ed25519_SCALARBYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_ed25519_scalarbytes(void); - -/* - * NOTE: Do not use the result of this function directly for key exchange. - * - * Hash the result with the public keys in order to compute a shared - * secret key: H(q || client_pk || server_pk) - * - * Or unless this is not an option, use the crypto_kx() API instead. - */ -SODIUM_EXPORT -int crypto_scalarmult_ed25519(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_scalarmult_ed25519_noclamp(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_scalarmult_ed25519_base(unsigned char *q, const unsigned char *n) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_scalarmult_ed25519_base_noclamp(unsigned char *q, const unsigned char *n) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_scalarmult_ristretto255.h b/win32/include/sodium/crypto_scalarmult_ristretto255.h deleted file mode 100644 index 40a45ccef0..0000000000 --- a/win32/include/sodium/crypto_scalarmult_ristretto255.h +++ /dev/null @@ -1,43 +0,0 @@ - -#ifndef crypto_scalarmult_ristretto255_H -#define crypto_scalarmult_ristretto255_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_scalarmult_ristretto255_BYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_ristretto255_bytes(void); - -#define crypto_scalarmult_ristretto255_SCALARBYTES 32U -SODIUM_EXPORT -size_t crypto_scalarmult_ristretto255_scalarbytes(void); - -/* - * NOTE: Do not use the result of this function directly for key exchange. - * - * Hash the result with the public keys in order to compute a shared - * secret key: H(q || client_pk || server_pk) - * - * Or unless this is not an option, use the crypto_kx() API instead. - */ -SODIUM_EXPORT -int crypto_scalarmult_ristretto255(unsigned char *q, const unsigned char *n, - const unsigned char *p) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_scalarmult_ristretto255_base(unsigned char *q, - const unsigned char *n) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_secretbox.h b/win32/include/sodium/crypto_secretbox.h deleted file mode 100644 index 1d3709db12..0000000000 --- a/win32/include/sodium/crypto_secretbox.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef crypto_secretbox_H -#define crypto_secretbox_H - -#include - -#include "crypto_secretbox_xsalsa20poly1305.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES -SODIUM_EXPORT -size_t crypto_secretbox_keybytes(void); - -#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES -SODIUM_EXPORT -size_t crypto_secretbox_noncebytes(void); - -#define crypto_secretbox_MACBYTES crypto_secretbox_xsalsa20poly1305_MACBYTES -SODIUM_EXPORT -size_t crypto_secretbox_macbytes(void); - -#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" -SODIUM_EXPORT -const char *crypto_secretbox_primitive(void); - -#define crypto_secretbox_MESSAGEBYTES_MAX crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX -SODIUM_EXPORT -size_t crypto_secretbox_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_secretbox_easy(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_detached(unsigned char *c, unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 5, 6))); - -SODIUM_EXPORT -int crypto_secretbox_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6))); - -SODIUM_EXPORT -void crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES]) - __attribute__ ((nonnull)); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_zerobytes(void); - -#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES -SODIUM_EXPORT -size_t crypto_secretbox_boxzerobytes(void); - -SODIUM_EXPORT -int crypto_secretbox(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_open(unsigned char *m, const unsigned char *c, - unsigned long long clen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_secretbox_xchacha20poly1305.h b/win32/include/sodium/crypto_secretbox_xchacha20poly1305.h deleted file mode 100644 index 6ec674e310..0000000000 --- a/win32/include/sodium/crypto_secretbox_xchacha20poly1305.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef crypto_secretbox_xchacha20poly1305_H -#define crypto_secretbox_xchacha20poly1305_H - -#include -#include "crypto_stream_xchacha20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xchacha20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_keybytes(void); - -#define crypto_secretbox_xchacha20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_noncebytes(void); - -#define crypto_secretbox_xchacha20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_macbytes(void); - -#define crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX \ - (crypto_stream_xchacha20_MESSAGEBYTES_MAX - crypto_secretbox_xchacha20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_secretbox_xchacha20poly1305_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_easy(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_detached(unsigned char *c, - unsigned char *mac, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 2, 5, 6))); - -SODIUM_EXPORT -int crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m, - const unsigned char *c, - const unsigned char *mac, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 3, 5, 6))); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_secretbox_xsalsa20poly1305.h b/win32/include/sodium/crypto_secretbox_xsalsa20poly1305.h deleted file mode 100644 index be0874cbaf..0000000000 --- a/win32/include/sodium/crypto_secretbox_xsalsa20poly1305.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef crypto_secretbox_xsalsa20poly1305_H -#define crypto_secretbox_xsalsa20poly1305_H - -#include -#include "crypto_stream_xsalsa20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretbox_xsalsa20poly1305_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_keybytes(void); - -#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_noncebytes(void); - -#define crypto_secretbox_xsalsa20poly1305_MACBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_macbytes(void); - -/* Only for the libsodium API - The NaCl compatibility API would require BOXZEROBYTES extra bytes */ -#define crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX \ - (crypto_stream_xsalsa20_MESSAGEBYTES_MAX - crypto_secretbox_xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305(unsigned char *c, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull(1, 4, 5))); - -SODIUM_EXPORT -int crypto_secretbox_xsalsa20poly1305_open(unsigned char *m, - const unsigned char *c, - unsigned long long clen, - const unsigned char *n, - const unsigned char *k) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(2, 4, 5))); - -SODIUM_EXPORT -void crypto_secretbox_xsalsa20poly1305_keygen(unsigned char k[crypto_secretbox_xsalsa20poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -/* -- NaCl compatibility interface ; Requires padding -- */ - -#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES 16U -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_boxzerobytes(void); - -#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES \ - (crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES + \ - crypto_secretbox_xsalsa20poly1305_MACBYTES) -SODIUM_EXPORT -size_t crypto_secretbox_xsalsa20poly1305_zerobytes(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_secretstream_xchacha20poly1305.h b/win32/include/sodium/crypto_secretstream_xchacha20poly1305.h deleted file mode 100644 index b22e4e9313..0000000000 --- a/win32/include/sodium/crypto_secretstream_xchacha20poly1305.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef crypto_secretstream_xchacha20poly1305_H -#define crypto_secretstream_xchacha20poly1305_H - -#include - -#include "crypto_aead_xchacha20poly1305.h" -#include "crypto_stream_chacha20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_secretstream_xchacha20poly1305_ABYTES \ - (1U + crypto_aead_xchacha20poly1305_ietf_ABYTES) -SODIUM_EXPORT -size_t crypto_secretstream_xchacha20poly1305_abytes(void); - -#define crypto_secretstream_xchacha20poly1305_HEADERBYTES \ - crypto_aead_xchacha20poly1305_ietf_NPUBBYTES -SODIUM_EXPORT -size_t crypto_secretstream_xchacha20poly1305_headerbytes(void); - -#define crypto_secretstream_xchacha20poly1305_KEYBYTES \ - crypto_aead_xchacha20poly1305_ietf_KEYBYTES -SODIUM_EXPORT -size_t crypto_secretstream_xchacha20poly1305_keybytes(void); - -#define crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX \ - SODIUM_MIN(SODIUM_SIZE_MAX - crypto_secretstream_xchacha20poly1305_ABYTES, \ - (64ULL * ((1ULL << 32) - 2ULL))) -SODIUM_EXPORT -size_t crypto_secretstream_xchacha20poly1305_messagebytes_max(void); - -#define crypto_secretstream_xchacha20poly1305_TAG_MESSAGE 0x00 -SODIUM_EXPORT -unsigned char crypto_secretstream_xchacha20poly1305_tag_message(void); - -#define crypto_secretstream_xchacha20poly1305_TAG_PUSH 0x01 -SODIUM_EXPORT -unsigned char crypto_secretstream_xchacha20poly1305_tag_push(void); - -#define crypto_secretstream_xchacha20poly1305_TAG_REKEY 0x02 -SODIUM_EXPORT -unsigned char crypto_secretstream_xchacha20poly1305_tag_rekey(void); - -#define crypto_secretstream_xchacha20poly1305_TAG_FINAL \ - (crypto_secretstream_xchacha20poly1305_TAG_PUSH | \ - crypto_secretstream_xchacha20poly1305_TAG_REKEY) -SODIUM_EXPORT -unsigned char crypto_secretstream_xchacha20poly1305_tag_final(void); - -typedef struct crypto_secretstream_xchacha20poly1305_state { - unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]; - unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES]; - unsigned char _pad[8]; -} crypto_secretstream_xchacha20poly1305_state; - -SODIUM_EXPORT -size_t crypto_secretstream_xchacha20poly1305_statebytes(void); - -SODIUM_EXPORT -void crypto_secretstream_xchacha20poly1305_keygen - (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_secretstream_xchacha20poly1305_init_push - (crypto_secretstream_xchacha20poly1305_state *state, - unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES], - const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_secretstream_xchacha20poly1305_push - (crypto_secretstream_xchacha20poly1305_state *state, - unsigned char *c, unsigned long long *clen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *ad, unsigned long long adlen, unsigned char tag) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_secretstream_xchacha20poly1305_init_pull - (crypto_secretstream_xchacha20poly1305_state *state, - const unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES], - const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_secretstream_xchacha20poly1305_pull - (crypto_secretstream_xchacha20poly1305_state *state, - unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, - const unsigned char *c, unsigned long long clen, - const unsigned char *ad, unsigned long long adlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -void crypto_secretstream_xchacha20poly1305_rekey - (crypto_secretstream_xchacha20poly1305_state *state); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_shorthash.h b/win32/include/sodium/crypto_shorthash.h deleted file mode 100644 index fecaa88bd8..0000000000 --- a/win32/include/sodium/crypto_shorthash.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef crypto_shorthash_H -#define crypto_shorthash_H - -#include - -#include "crypto_shorthash_siphash24.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_shorthash_BYTES crypto_shorthash_siphash24_BYTES -SODIUM_EXPORT -size_t crypto_shorthash_bytes(void); - -#define crypto_shorthash_KEYBYTES crypto_shorthash_siphash24_KEYBYTES -SODIUM_EXPORT -size_t crypto_shorthash_keybytes(void); - -#define crypto_shorthash_PRIMITIVE "siphash24" -SODIUM_EXPORT -const char *crypto_shorthash_primitive(void); - -SODIUM_EXPORT -int crypto_shorthash(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -void crypto_shorthash_keygen(unsigned char k[crypto_shorthash_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_shorthash_siphash24.h b/win32/include/sodium/crypto_shorthash_siphash24.h deleted file mode 100644 index 1e6f72a620..0000000000 --- a/win32/include/sodium/crypto_shorthash_siphash24.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef crypto_shorthash_siphash24_H -#define crypto_shorthash_siphash24_H - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -/* -- 64-bit output -- */ - -#define crypto_shorthash_siphash24_BYTES 8U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_bytes(void); - -#define crypto_shorthash_siphash24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphash24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull(1, 4))); - -#ifndef SODIUM_LIBRARY_MINIMAL -/* -- 128-bit output -- */ - -#define crypto_shorthash_siphashx24_BYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_bytes(void); - -#define crypto_shorthash_siphashx24_KEYBYTES 16U -SODIUM_EXPORT -size_t crypto_shorthash_siphashx24_keybytes(void); - -SODIUM_EXPORT -int crypto_shorthash_siphashx24(unsigned char *out, const unsigned char *in, - unsigned long long inlen, const unsigned char *k) - __attribute__ ((nonnull(1, 4))); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_sign.h b/win32/include/sodium/crypto_sign.h deleted file mode 100644 index f5fafb123e..0000000000 --- a/win32/include/sodium/crypto_sign.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef crypto_sign_H -#define crypto_sign_H - -/* - * THREAD SAFETY: crypto_sign_keypair() is thread-safe, - * provided that sodium_init() was called before. - * - * Other functions, including crypto_sign_seed_keypair() are always thread-safe. - */ - -#include - -#include "crypto_sign_ed25519.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef crypto_sign_ed25519ph_state crypto_sign_state; - -SODIUM_EXPORT -size_t crypto_sign_statebytes(void); - -#define crypto_sign_BYTES crypto_sign_ed25519_BYTES -SODIUM_EXPORT -size_t crypto_sign_bytes(void); - -#define crypto_sign_SEEDBYTES crypto_sign_ed25519_SEEDBYTES -SODIUM_EXPORT -size_t crypto_sign_seedbytes(void); - -#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_publickeybytes(void); - -#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES -SODIUM_EXPORT -size_t crypto_sign_secretkeybytes(void); - -#define crypto_sign_MESSAGEBYTES_MAX crypto_sign_ed25519_MESSAGEBYTES_MAX -SODIUM_EXPORT -size_t crypto_sign_messagebytes_max(void); - -#define crypto_sign_PRIMITIVE "ed25519" -SODIUM_EXPORT -const char *crypto_sign_primitive(void); - -SODIUM_EXPORT -int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_keypair(unsigned char *pk, unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk) __attribute__ ((nonnull(1, 5))); - -SODIUM_EXPORT -int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5))); - -SODIUM_EXPORT -int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk) __attribute__ ((nonnull(1, 5))); - -SODIUM_EXPORT -int crypto_sign_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_sign_init(crypto_sign_state *state); - -SODIUM_EXPORT -int crypto_sign_update(crypto_sign_state *state, - const unsigned char *m, unsigned long long mlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk) - __attribute__ ((nonnull(1, 2, 4))); - -SODIUM_EXPORT -int crypto_sign_final_verify(crypto_sign_state *state, const unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_sign_ed25519.h b/win32/include/sodium/crypto_sign_ed25519.h deleted file mode 100644 index 0fdac42d35..0000000000 --- a/win32/include/sodium/crypto_sign_ed25519.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef crypto_sign_ed25519_H -#define crypto_sign_ed25519_H - -#include -#include "crypto_hash_sha512.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct crypto_sign_ed25519ph_state { - crypto_hash_sha512_state hs; -} crypto_sign_ed25519ph_state; - -SODIUM_EXPORT -size_t crypto_sign_ed25519ph_statebytes(void); - -#define crypto_sign_ed25519_BYTES 64U -SODIUM_EXPORT -size_t crypto_sign_ed25519_bytes(void); - -#define crypto_sign_ed25519_SEEDBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_seedbytes(void); - -#define crypto_sign_ed25519_PUBLICKEYBYTES 32U -SODIUM_EXPORT -size_t crypto_sign_ed25519_publickeybytes(void); - -#define crypto_sign_ed25519_SECRETKEYBYTES (32U + 32U) -SODIUM_EXPORT -size_t crypto_sign_ed25519_secretkeybytes(void); - -#define crypto_sign_ed25519_MESSAGEBYTES_MAX (SODIUM_SIZE_MAX - crypto_sign_ed25519_BYTES) -SODIUM_EXPORT -size_t crypto_sign_ed25519_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen_p, - const unsigned char *m, unsigned long long mlen, - const unsigned char *sk) - __attribute__ ((nonnull(1, 5))); - -SODIUM_EXPORT -int crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen_p, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(3, 5))); - -SODIUM_EXPORT -int crypto_sign_ed25519_detached(unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk) - __attribute__ ((nonnull(1, 5))); - -SODIUM_EXPORT -int crypto_sign_ed25519_verify_detached(const unsigned char *sig, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull(1, 4))); - -SODIUM_EXPORT -int crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, - const unsigned char *seed) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk, - const unsigned char *ed25519_pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk, - const unsigned char *ed25519_sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, - const unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_update(crypto_sign_ed25519ph_state *state, - const unsigned char *m, - unsigned long long mlen) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_create(crypto_sign_ed25519ph_state *state, - unsigned char *sig, - unsigned long long *siglen_p, - const unsigned char *sk) - __attribute__ ((nonnull(1, 2, 4))); - -SODIUM_EXPORT -int crypto_sign_ed25519ph_final_verify(crypto_sign_ed25519ph_state *state, - const unsigned char *sig, - const unsigned char *pk) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_sign_edwards25519sha512batch.h b/win32/include/sodium/crypto_sign_edwards25519sha512batch.h deleted file mode 100644 index eed158aa84..0000000000 --- a/win32/include/sodium/crypto_sign_edwards25519sha512batch.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef crypto_sign_edwards25519sha512batch_H -#define crypto_sign_edwards25519sha512batch_H - -/* - * WARNING: This construction was a prototype, which should not be used - * any more in new projects. - * - * crypto_sign_edwards25519sha512batch is provided for applications - * initially built with NaCl, but as recommended by the author of this - * construction, new applications should use ed25519 instead. - * - * In Sodium, you should use the high-level crypto_sign_*() functions instead. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_sign_edwards25519sha512batch_BYTES 64U -#define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES 32U -#define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES (32U + 32U) -#define crypto_sign_edwards25519sha512batch_MESSAGEBYTES_MAX (SODIUM_SIZE_MAX - crypto_sign_edwards25519sha512batch_BYTES) - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch(unsigned char *sm, - unsigned long long *smlen_p, - const unsigned char *m, - unsigned long long mlen, - const unsigned char *sk) - __attribute__ ((deprecated)) __attribute__ ((nonnull(1, 5))); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_open(unsigned char *m, - unsigned long long *mlen_p, - const unsigned char *sm, - unsigned long long smlen, - const unsigned char *pk) - __attribute__ ((deprecated)) __attribute__ ((nonnull(3, 5))); - -SODIUM_EXPORT -int crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, - unsigned char *sk) - __attribute__ ((deprecated)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream.h b/win32/include/sodium/crypto_stream.h deleted file mode 100644 index 88dab5f611..0000000000 --- a/win32/include/sodium/crypto_stream.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef crypto_stream_H -#define crypto_stream_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include - -#include "crypto_stream_xsalsa20.h" -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES -SODIUM_EXPORT -size_t crypto_stream_keybytes(void); - -#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES -SODIUM_EXPORT -size_t crypto_stream_noncebytes(void); - -#define crypto_stream_MESSAGEBYTES_MAX crypto_stream_xsalsa20_MESSAGEBYTES_MAX -SODIUM_EXPORT -size_t crypto_stream_messagebytes_max(void); - -#define crypto_stream_PRIMITIVE "xsalsa20" -SODIUM_EXPORT -const char *crypto_stream_primitive(void); - -SODIUM_EXPORT -int crypto_stream(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_keygen(unsigned char k[crypto_stream_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_chacha20.h b/win32/include/sodium/crypto_stream_chacha20.h deleted file mode 100644 index 408897558b..0000000000 --- a/win32/include/sodium/crypto_stream_chacha20.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef crypto_stream_chacha20_H -#define crypto_stream_chacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_chacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_keybytes(void); - -#define crypto_stream_chacha20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_chacha20_noncebytes(void); - -#define crypto_stream_chacha20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_stream_chacha20_messagebytes_max(void); - -/* ChaCha20 with a 64-bit nonce and a 64-bit counter, as originally designed */ - -SODIUM_EXPORT -int crypto_stream_chacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]) - __attribute__ ((nonnull)); - -/* ChaCha20 with a 96-bit nonce and a 32-bit counter (IETF) */ - -#define crypto_stream_chacha20_ietf_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_keybytes(void); - -#define crypto_stream_chacha20_ietf_NONCEBYTES 12U -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_noncebytes(void); - -#define crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX \ - SODIUM_MIN(SODIUM_SIZE_MAX, 64ULL * (1ULL << 32)) -SODIUM_EXPORT -size_t crypto_stream_chacha20_ietf_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint32_t ic, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]) - __attribute__ ((nonnull)); - -/* Aliases */ - -#define crypto_stream_chacha20_IETF_KEYBYTES crypto_stream_chacha20_ietf_KEYBYTES -#define crypto_stream_chacha20_IETF_NONCEBYTES crypto_stream_chacha20_ietf_NONCEBYTES -#define crypto_stream_chacha20_IETF_MESSAGEBYTES_MAX crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_salsa20.h b/win32/include/sodium/crypto_stream_salsa20.h deleted file mode 100644 index 45b3b3e34a..0000000000 --- a/win32/include/sodium/crypto_stream_salsa20.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef crypto_stream_salsa20_H -#define crypto_stream_salsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa20_keybytes(void); - -#define crypto_stream_salsa20_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa20_noncebytes(void); - -#define crypto_stream_salsa20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_stream_salsa20_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_stream_salsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_salsa2012.h b/win32/include/sodium/crypto_stream_salsa2012.h deleted file mode 100644 index 6c5d303cac..0000000000 --- a/win32/include/sodium/crypto_stream_salsa2012.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef crypto_stream_salsa2012_H -#define crypto_stream_salsa2012_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa2012_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_keybytes(void); - -#define crypto_stream_salsa2012_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa2012_noncebytes(void); - -#define crypto_stream_salsa2012_MESSAGEBYTES_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_stream_salsa2012_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_stream_salsa2012(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_salsa208.h b/win32/include/sodium/crypto_stream_salsa208.h deleted file mode 100644 index d574f30478..0000000000 --- a/win32/include/sodium/crypto_stream_salsa208.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef crypto_stream_salsa208_H -#define crypto_stream_salsa208_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_salsa208_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_salsa208_keybytes(void) - __attribute__ ((deprecated)); - -#define crypto_stream_salsa208_NONCEBYTES 8U -SODIUM_EXPORT -size_t crypto_stream_salsa208_noncebytes(void) - __attribute__ ((deprecated)); - -#define crypto_stream_salsa208_MESSAGEBYTES_MAX SODIUM_SIZE_MAX - SODIUM_EXPORT -size_t crypto_stream_salsa208_messagebytes_max(void) - __attribute__ ((deprecated)); - -SODIUM_EXPORT -int crypto_stream_salsa208(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((deprecated)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_salsa208_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((deprecated)) __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_salsa208_keygen(unsigned char k[crypto_stream_salsa208_KEYBYTES]) - __attribute__ ((deprecated)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_xchacha20.h b/win32/include/sodium/crypto_stream_xchacha20.h deleted file mode 100644 index c4002db00a..0000000000 --- a/win32/include/sodium/crypto_stream_xchacha20.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef crypto_stream_xchacha20_H -#define crypto_stream_xchacha20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xchacha20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_keybytes(void); - -#define crypto_stream_xchacha20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xchacha20_noncebytes(void); - -#define crypto_stream_xchacha20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_stream_xchacha20_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_stream_xchacha20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_xchacha20_keygen(unsigned char k[crypto_stream_xchacha20_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_stream_xsalsa20.h b/win32/include/sodium/crypto_stream_xsalsa20.h deleted file mode 100644 index 20034e3462..0000000000 --- a/win32/include/sodium/crypto_stream_xsalsa20.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef crypto_stream_xsalsa20_H -#define crypto_stream_xsalsa20_H - -/* - * WARNING: This is just a stream cipher. It is NOT authenticated encryption. - * While it provides some protection against eavesdropping, it does NOT - * provide any security against active attacks. - * Unless you know what you're doing, what you are looking for is probably - * the crypto_box functions. - */ - -#include -#include -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -#define crypto_stream_xsalsa20_KEYBYTES 32U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_keybytes(void); - -#define crypto_stream_xsalsa20_NONCEBYTES 24U -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_noncebytes(void); - -#define crypto_stream_xsalsa20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX -SODIUM_EXPORT -size_t crypto_stream_xsalsa20_messagebytes_max(void); - -SODIUM_EXPORT -int crypto_stream_xsalsa20(unsigned char *c, unsigned long long clen, - const unsigned char *n, const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor(unsigned char *c, const unsigned char *m, - unsigned long long mlen, const unsigned char *n, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *m, - unsigned long long mlen, - const unsigned char *n, uint64_t ic, - const unsigned char *k) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void crypto_stream_xsalsa20_keygen(unsigned char k[crypto_stream_xsalsa20_KEYBYTES]) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_verify_16.h b/win32/include/sodium/crypto_verify_16.h deleted file mode 100644 index 7b9c8077ad..0000000000 --- a/win32/include/sodium/crypto_verify_16.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_16_H -#define crypto_verify_16_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_16_BYTES 16U -SODIUM_EXPORT -size_t crypto_verify_16_bytes(void); - -SODIUM_EXPORT -int crypto_verify_16(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_verify_32.h b/win32/include/sodium/crypto_verify_32.h deleted file mode 100644 index 9b0f4529f6..0000000000 --- a/win32/include/sodium/crypto_verify_32.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_32_H -#define crypto_verify_32_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_32_BYTES 32U -SODIUM_EXPORT -size_t crypto_verify_32_bytes(void); - -SODIUM_EXPORT -int crypto_verify_32(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/crypto_verify_64.h b/win32/include/sodium/crypto_verify_64.h deleted file mode 100644 index c83b73025a..0000000000 --- a/win32/include/sodium/crypto_verify_64.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef crypto_verify_64_H -#define crypto_verify_64_H - -#include -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define crypto_verify_64_BYTES 64U -SODIUM_EXPORT -size_t crypto_verify_64_bytes(void); - -SODIUM_EXPORT -int crypto_verify_64(const unsigned char *x, const unsigned char *y) - __attribute__ ((warn_unused_result)) __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/export.h b/win32/include/sodium/export.h deleted file mode 100644 index a0074fc9cb..0000000000 --- a/win32/include/sodium/export.h +++ /dev/null @@ -1,57 +0,0 @@ - -#ifndef sodium_export_H -#define sodium_export_H - -#include -#include -#include - -#if !defined(__clang__) && !defined(__GNUC__) -# ifdef __attribute__ -# undef __attribute__ -# endif -# define __attribute__(a) -#endif - -#ifdef SODIUM_STATIC -# define SODIUM_EXPORT -# define SODIUM_EXPORT_WEAK -#else -# if defined(_MSC_VER) -# ifdef SODIUM_DLL_EXPORT -# define SODIUM_EXPORT __declspec(dllexport) -# else -# define SODIUM_EXPORT __declspec(dllimport) -# endif -# else -# if defined(__SUNPRO_C) -# ifndef __GNU_C__ -# define SODIUM_EXPORT __attribute__ (visibility(__global)) -# else -# define SODIUM_EXPORT __attribute__ __global -# endif -# elif defined(_MSG_VER) -# define SODIUM_EXPORT extern __declspec(dllexport) -# else -# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) -# endif -# endif -# if defined(__ELF__) && !defined(SODIUM_DISABLE_WEAK_FUNCTIONS) -# define SODIUM_EXPORT_WEAK SODIUM_EXPORT __attribute__((weak)) -# else -# define SODIUM_EXPORT_WEAK SODIUM_EXPORT -# endif -#endif - -#ifndef CRYPTO_ALIGN -# if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# define CRYPTO_ALIGN(x) __declspec(align(x)) -# else -# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) -# endif -#endif - -#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B)) -#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX) - -#endif diff --git a/win32/include/sodium/randombytes.h b/win32/include/sodium/randombytes.h deleted file mode 100644 index a03cc65720..0000000000 --- a/win32/include/sodium/randombytes.h +++ /dev/null @@ -1,72 +0,0 @@ - -#ifndef randombytes_H -#define randombytes_H - -#include -#include - -#include - -#include "export.h" - -#ifdef __cplusplus -# ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wlong-long" -# endif -extern "C" { -#endif - -typedef struct randombytes_implementation { - const char *(*implementation_name)(void); /* required */ - uint32_t (*random)(void); /* required */ - void (*stir)(void); /* optional */ - uint32_t (*uniform)(const uint32_t upper_bound); /* optional, a default implementation will be used if NULL */ - void (*buf)(void * const buf, const size_t size); /* required */ - int (*close)(void); /* optional */ -} randombytes_implementation; - -#define randombytes_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 0xffffffffUL) - -#define randombytes_SEEDBYTES 32U -SODIUM_EXPORT -size_t randombytes_seedbytes(void); - -SODIUM_EXPORT -void randombytes_buf(void * const buf, const size_t size) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -void randombytes_buf_deterministic(void * const buf, const size_t size, - const unsigned char seed[randombytes_SEEDBYTES]) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -uint32_t randombytes_random(void); - -SODIUM_EXPORT -uint32_t randombytes_uniform(const uint32_t upper_bound); - -SODIUM_EXPORT -void randombytes_stir(void); - -SODIUM_EXPORT -int randombytes_close(void); - -SODIUM_EXPORT -int randombytes_set_implementation(randombytes_implementation *impl) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -const char *randombytes_implementation_name(void); - -/* -- NaCl compatibility interface -- */ - -SODIUM_EXPORT -void randombytes(unsigned char * const buf, const unsigned long long buf_len) - __attribute__ ((nonnull)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/randombytes_internal_random.h b/win32/include/sodium/randombytes_internal_random.h deleted file mode 100644 index 2b2b7d6edc..0000000000 --- a/win32/include/sodium/randombytes_internal_random.h +++ /dev/null @@ -1,22 +0,0 @@ - -#ifndef randombytes_internal_random_H -#define randombytes_internal_random_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_internal_implementation; - -/* Backwards compatibility with libsodium < 1.0.18 */ -#define randombytes_salsa20_implementation randombytes_internal_implementation - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/randombytes_sysrandom.h b/win32/include/sodium/randombytes_sysrandom.h deleted file mode 100644 index 9e27b674c7..0000000000 --- a/win32/include/sodium/randombytes_sysrandom.h +++ /dev/null @@ -1,19 +0,0 @@ - -#ifndef randombytes_sysrandom_H -#define randombytes_sysrandom_H - -#include "export.h" -#include "randombytes.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -extern struct randombytes_implementation randombytes_sysrandom_implementation; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/runtime.h b/win32/include/sodium/runtime.h deleted file mode 100644 index 7f15d58e7c..0000000000 --- a/win32/include/sodium/runtime.h +++ /dev/null @@ -1,52 +0,0 @@ - -#ifndef sodium_runtime_H -#define sodium_runtime_H - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_neon(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_sse2(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_sse3(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_ssse3(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_sse41(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_avx(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_avx2(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_avx512f(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_pclmul(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_aesni(void); - -SODIUM_EXPORT_WEAK -int sodium_runtime_has_rdrand(void); - -/* ------------------------------------------------------------------------- */ - -int _sodium_runtime_get_cpu_features(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/utils.h b/win32/include/sodium/utils.h deleted file mode 100644 index ac80151291..0000000000 --- a/win32/include/sodium/utils.h +++ /dev/null @@ -1,179 +0,0 @@ - -#ifndef sodium_utils_H -#define sodium_utils_H - -#include - -#include "export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef SODIUM_C99 -# if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L -# define SODIUM_C99(X) -# else -# define SODIUM_C99(X) X -# endif -#endif - -SODIUM_EXPORT -void sodium_memzero(void * const pnt, const size_t len); - -SODIUM_EXPORT -void sodium_stackzero(const size_t len); - -/* - * WARNING: sodium_memcmp() must be used to verify if two secret keys - * are equal, in constant time. - * It returns 0 if the keys are equal, and -1 if they differ. - * This function is not designed for lexicographical comparisons. - */ -SODIUM_EXPORT -int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) - __attribute__ ((warn_unused_result)); - -/* - * sodium_compare() returns -1 if b1_ < b2_, 1 if b1_ > b2_ and 0 if b1_ == b2_ - * It is suitable for lexicographical comparisons, or to compare nonces - * and counters stored in little-endian format. - * However, it is slower than sodium_memcmp(). - */ -SODIUM_EXPORT -int sodium_compare(const unsigned char *b1_, const unsigned char *b2_, - size_t len) __attribute__ ((warn_unused_result)); - -SODIUM_EXPORT -int sodium_is_zero(const unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_increment(unsigned char *n, const size_t nlen); - -SODIUM_EXPORT -void sodium_add(unsigned char *a, const unsigned char *b, const size_t len); - -SODIUM_EXPORT -void sodium_sub(unsigned char *a, const unsigned char *b, const size_t len); - -SODIUM_EXPORT -char *sodium_bin2hex(char * const hex, const size_t hex_maxlen, - const unsigned char * const bin, const size_t bin_len) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, - const char * const hex, const size_t hex_len, - const char * const ignore, size_t * const bin_len, - const char ** const hex_end) - __attribute__ ((nonnull(1))); - -#define sodium_base64_VARIANT_ORIGINAL 1 -#define sodium_base64_VARIANT_ORIGINAL_NO_PADDING 3 -#define sodium_base64_VARIANT_URLSAFE 5 -#define sodium_base64_VARIANT_URLSAFE_NO_PADDING 7 - -/* - * Computes the required length to encode BIN_LEN bytes as a base64 string - * using the given variant. The computed length includes a trailing \0. - */ -#define sodium_base64_ENCODED_LEN(BIN_LEN, VARIANT) \ - (((BIN_LEN) / 3U) * 4U + \ - ((((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) | (((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) >> 1)) & 1U) * \ - (4U - (~((((VARIANT) & 2U) >> 1) - 1U) & (3U - ((BIN_LEN) - ((BIN_LEN) / 3U) * 3U)))) + 1U) - -SODIUM_EXPORT -size_t sodium_base64_encoded_len(const size_t bin_len, const int variant); - -SODIUM_EXPORT -char *sodium_bin2base64(char * const b64, const size_t b64_maxlen, - const unsigned char * const bin, const size_t bin_len, - const int variant) __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, - const char * const b64, const size_t b64_len, - const char * const ignore, size_t * const bin_len, - const char ** const b64_end, const int variant) - __attribute__ ((nonnull(1))); - -SODIUM_EXPORT -int sodium_mlock(void * const addr, const size_t len) - __attribute__ ((nonnull)); - -SODIUM_EXPORT -int sodium_munlock(void * const addr, const size_t len) - __attribute__ ((nonnull)); - -/* WARNING: sodium_malloc() and sodium_allocarray() are not general-purpose - * allocation functions. - * - * They return a pointer to a region filled with 0xd0 bytes, immediately - * followed by a guard page. - * As a result, accessing a single byte after the requested allocation size - * will intentionally trigger a segmentation fault. - * - * A canary and an additional guard page placed before the beginning of the - * region may also kill the process if a buffer underflow is detected. - * - * The memory layout is: - * [unprotected region size (read only)][guard page (no access)][unprotected pages (read/write)][guard page (no access)] - * With the layout of the unprotected pages being: - * [optional padding][16-bytes canary][user region] - * - * However: - * - These functions are significantly slower than standard functions - * - Each allocation requires 3 or 4 additional pages - * - The returned address will not be aligned if the allocation size is not - * a multiple of the required alignment. For this reason, these functions - * are designed to store data, such as secret keys and messages. - * - * sodium_malloc() can be used to allocate any libsodium data structure. - * - * The crypto_generichash_state structure is packed and its length is - * either 357 or 361 bytes. For this reason, when using sodium_malloc() to - * allocate a crypto_generichash_state structure, padding must be added in - * order to ensure proper alignment. crypto_generichash_statebytes() - * returns the rounded up structure size, and should be prefered to sizeof(): - * state = sodium_malloc(crypto_generichash_statebytes()); - */ - -SODIUM_EXPORT -void *sodium_malloc(const size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void *sodium_allocarray(size_t count, size_t size) - __attribute__ ((malloc)); - -SODIUM_EXPORT -void sodium_free(void *ptr); - -SODIUM_EXPORT -int sodium_mprotect_noaccess(void *ptr) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int sodium_mprotect_readonly(void *ptr) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int sodium_mprotect_readwrite(void *ptr) __attribute__ ((nonnull)); - -SODIUM_EXPORT -int sodium_pad(size_t *padded_buflen_p, unsigned char *buf, - size_t unpadded_buflen, size_t blocksize, size_t max_buflen) - __attribute__ ((nonnull(2))); - -SODIUM_EXPORT -int sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf, - size_t padded_buflen, size_t blocksize) - __attribute__ ((nonnull(2))); - -/* -------- */ - -int _sodium_alloc_init(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/win32/include/sodium/version.h b/win32/include/sodium/version.h deleted file mode 100644 index 201a290e7d..0000000000 --- a/win32/include/sodium/version.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef sodium_version_H -#define sodium_version_H - -#include "export.h" - -#define SODIUM_VERSION_STRING "1.0.18" - -#define SODIUM_LIBRARY_VERSION_MAJOR 10 -#define SODIUM_LIBRARY_VERSION_MINOR 3 - - -#ifdef __cplusplus -extern "C" { -#endif - -SODIUM_EXPORT -const char *sodium_version_string(void); - -SODIUM_EXPORT -int sodium_library_version_major(void); - -SODIUM_EXPORT -int sodium_library_version_minor(void); - -SODIUM_EXPORT -int sodium_library_minimal(void); - -#ifdef __cplusplus -} -#endif - -#endif From 5110945ae8a263b9956c40efad4c9eb23c63fdc2 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Fri, 11 Oct 2024 10:07:01 +0100 Subject: [PATCH 65/99] refactor: remove unused debug variable (#1266) --- src/dpp/voice/enabled/opus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp index 9f8aaeaff9..5eb7a77cc4 100644 --- a/src/dpp/voice/enabled/opus.cpp +++ b/src/dpp/voice/enabled/opus.cpp @@ -117,7 +117,6 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet size_t packet_siz = sizeof(header) + (encoded_audio_length + ssl_crypto_aead_xchacha20poly1305_IETF_ABYTES) + sizeof(packet_nonce); std::vector payload(packet_siz); - std::vector payload2(packet_siz); /* Set RTP header */ std::memcpy(payload.data(), &header, sizeof(header)); From 6134d8da41179b8d2e0a4276570705d05e3e38b2 Mon Sep 17 00:00:00 2001 From: Miuna <809711+Mishura4@users.noreply.github.com> Date: Fri, 11 Oct 2024 14:28:42 -0400 Subject: [PATCH 66/99] docs: prevent "The Windows 7 Incident" (#1267) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f0a658892a..953da47cb6 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ You can find more examples in our [example page](https://dpp.dev/example-program ## 💻 Supported Systems +We support the following OS families, as long as they are still officially supported by their provider. **We will provide no support for operating systems past end-of-life**. + ### Linux The library runs ideally on **Linux**. From a1a32d227a49d92e637d3311468cc53508e6e446 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Sat, 12 Oct 2024 13:37:27 +0100 Subject: [PATCH 67/99] fix: crash in threads_get_public_archived (#1268) --- src/dpp/thread.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/dpp/thread.cpp b/src/dpp/thread.cpp index 8cfe5d618a..af661fe663 100644 --- a/src/dpp/thread.cpp +++ b/src/dpp/thread.cpp @@ -46,12 +46,14 @@ thread& thread::fill_from_json_impl(json* j) { set_int8_not_null(j, "member_count", this->member_count); set_bool_not_null(j, "newly_created", this->newly_created); - auto json_metadata = (*j)["thread_metadata"]; - metadata.archived = bool_not_null(&json_metadata, "archived"); - metadata.archive_timestamp = ts_not_null(&json_metadata, "archive_timestamp"); - metadata.auto_archive_duration = int16_not_null(&json_metadata, "auto_archive_duration"); - metadata.locked = bool_not_null(&json_metadata, "locked"); - metadata.invitable = bool_not_null(&json_metadata, "invitable"); + if (j->contains("thread_metadata")) { + auto json_metadata = (*j)["thread_metadata"]; + metadata.archived = bool_not_null(&json_metadata, "archived"); + metadata.archive_timestamp = ts_not_null(&json_metadata, "archive_timestamp"); + metadata.auto_archive_duration = int16_not_null(&json_metadata, "auto_archive_duration"); + metadata.locked = bool_not_null(&json_metadata, "locked"); + metadata.invitable = bool_not_null(&json_metadata, "invitable"); + } /* Only certain events set this */ if (j->contains("member")) { From 20bc7cb8b4d9c8d97d50f26b0f6c25a64fc69bc2 Mon Sep 17 00:00:00 2001 From: DPP VCPKG Bot Date: Sat, 12 Oct 2024 14:09:16 +0000 Subject: [PATCH 68/99] [bot] VCPKG info update [skip ci] --- vcpkg/ports/dpp/portfile.cmake | 2 +- vcpkg/ports/dpp/vcpkg.json | 2 +- vcpkg/versions/baseline.json | 610 +++++++++++++++++---------------- vcpkg/versions/d-/dpp.json | 5 + 4 files changed, 316 insertions(+), 303 deletions(-) diff --git a/vcpkg/ports/dpp/portfile.cmake b/vcpkg/ports/dpp/portfile.cmake index 1302502ed9..0af92ac4df 100644 --- a/vcpkg/ports/dpp/portfile.cmake +++ b/vcpkg/ports/dpp/portfile.cmake @@ -2,7 +2,7 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO brainboxdotcc/DPP REF "v${VERSION}" - SHA512 0aac06f8ee67e3b4c430c9844beb6bdc3e31adebfcb2c077d18be8a8295451d70735f96dd5316d299df30b4cc4229180ffbad5095e51b49adf182290a8133a90 + SHA512 664f669ecb2d8cafdfa6dd776fb429cde7d5692157d34f300ffe42cb7711dec69ce194ece5d372c8b070f979e2a341ecb7c018f8825a8acc148d17b3d4043c9b ) vcpkg_cmake_configure( diff --git a/vcpkg/ports/dpp/vcpkg.json b/vcpkg/ports/dpp/vcpkg.json index 743b89dd0b..05c1946a7b 100644 --- a/vcpkg/ports/dpp/vcpkg.json +++ b/vcpkg/ports/dpp/vcpkg.json @@ -1,6 +1,6 @@ { "name": "dpp", - "version": "10.0.31", + "version": "10.0.32", "description": "D++ Extremely Lightweight C++ Discord Library.", "homepage": "https://dpp.dev/", "license": "Apache-2.0", diff --git a/vcpkg/versions/baseline.json b/vcpkg/versions/baseline.json index 4e4454f9ba..bd267a5c4d 100644 --- a/vcpkg/versions/baseline.json +++ b/vcpkg/versions/baseline.json @@ -25,7 +25,7 @@ "port-version": 3 }, "ace": { - "baseline": "8.0.0", + "baseline": "8.0.1", "port-version": 0 }, "acl": { @@ -37,7 +37,7 @@ "port-version": 16 }, "ada-url": { - "baseline": "2.9.1", + "baseline": "2.9.2", "port-version": 0 }, "ade": { @@ -61,7 +61,7 @@ "port-version": 1 }, "aklomp-base64": { - "baseline": "0.5.1", + "baseline": "0.5.2", "port-version": 0 }, "alac": { @@ -73,7 +73,7 @@ "port-version": 7 }, "alembic": { - "baseline": "1.8.6", + "baseline": "1.8.7", "port-version": 0 }, "aliyun-oss-c-sdk": { @@ -93,7 +93,7 @@ "port-version": 0 }, "alpaka": { - "baseline": "1.1.0", + "baseline": "1.2.0", "port-version": 0 }, "alsa": { @@ -105,24 +105,24 @@ "port-version": 0 }, "amd-amf": { - "baseline": "1.4.33", - "port-version": 1 + "baseline": "1.4.35", + "port-version": 0 }, "ampl-asl": { - "baseline": "2020-11-11", - "port-version": 3 + "baseline": "2024-02-01", + "port-version": 0 }, "ampl-mp": { "baseline": "2020-11-11", - "port-version": 4 + "port-version": 5 }, "amqpcpp": { "baseline": "4.3.26", "port-version": 0 }, "anari": { - "baseline": "0.7.0", - "port-version": 1 + "baseline": "0.10.0", + "port-version": 0 }, "anax": { "baseline": "2.1.0", @@ -145,7 +145,7 @@ "port-version": 0 }, "antlr4": { - "baseline": "4.13.1", + "baseline": "4.13.2", "port-version": 0 }, "any-lite": { @@ -242,14 +242,14 @@ }, "arrayfire": { "baseline": "3.8.0", - "port-version": 6 + "port-version": 7 }, "arrow": { "baseline": "17.0.0", "port-version": 0 }, "arsenalgear": { - "baseline": "2.1.0", + "baseline": "2.1.1", "port-version": 0 }, "ashes": { @@ -281,7 +281,7 @@ "port-version": 1 }, "assimp": { - "baseline": "5.4.2", + "baseline": "5.4.3", "port-version": 0 }, "astr": { @@ -289,7 +289,7 @@ "port-version": 0 }, "async-mqtt": { - "baseline": "9.0.0", + "baseline": "9.0.1", "port-version": 0 }, "async-simple": { @@ -333,7 +333,7 @@ "port-version": 3 }, "atomic-queue": { - "baseline": "1.6.3", + "baseline": "1.6.5", "port-version": 0 }, "attr": { @@ -385,27 +385,27 @@ "port-version": 0 }, "aws-c-auth": { - "baseline": "0.7.22", + "baseline": "0.7.31", "port-version": 0 }, "aws-c-cal": { - "baseline": "0.6.15", + "baseline": "0.7.4", "port-version": 0 }, "aws-c-common": { - "baseline": "0.9.21", + "baseline": "0.9.28", "port-version": 0 }, "aws-c-compression": { - "baseline": "0.2.18", + "baseline": "0.2.19", "port-version": 0 }, "aws-c-event-stream": { - "baseline": "0.4.2", + "baseline": "0.4.3", "port-version": 0 }, "aws-c-http": { - "baseline": "0.8.2", + "baseline": "0.8.10", "port-version": 0 }, "aws-c-io": { @@ -413,23 +413,23 @@ "port-version": 0 }, "aws-c-mqtt": { - "baseline": "0.10.5", + "baseline": "0.10.7", "port-version": 0 }, "aws-c-s3": { - "baseline": "0.5.10", + "baseline": "0.6.6", "port-version": 0 }, "aws-c-sdkutils": { - "baseline": "0.1.16", + "baseline": "0.1.19", "port-version": 0 }, "aws-checksums": { - "baseline": "0.1.18", + "baseline": "0.1.20", "port-version": 0 }, "aws-crt-cpp": { - "baseline": "0.26.12", + "baseline": "0.28.3", "port-version": 0 }, "aws-lambda-cpp": { @@ -437,7 +437,7 @@ "port-version": 0 }, "aws-sdk-cpp": { - "baseline": "1.11.352", + "baseline": "1.11.420", "port-version": 0 }, "azmq": { @@ -453,20 +453,20 @@ "port-version": 0 }, "azure-core-cpp": { - "baseline": "1.13.0", + "baseline": "1.14.0", "port-version": 0 }, "azure-core-tracing-opentelemetry-cpp": { "baseline": "1.0.0-beta.4", - "port-version": 3 + "port-version": 4 }, "azure-data-tables-cpp": { "baseline": "1.0.0-beta.4", "port-version": 0 }, "azure-identity-cpp": { - "baseline": "1.9.0", - "port-version": 0 + "baseline": "1.10.0", + "port-version": 1 }, "azure-iot-sdk-c": { "baseline": "2024-08-12", @@ -482,15 +482,15 @@ }, "azure-messaging-eventhubs-checkpointstore-blob-cpp": { "baseline": "1.0.0-beta.1", - "port-version": 2 + "port-version": 3 }, "azure-messaging-eventhubs-cpp": { "baseline": "1.0.0-beta.9", - "port-version": 0 + "port-version": 1 }, "azure-security-attestation-cpp": { "baseline": "1.1.0", - "port-version": 4 + "port-version": 5 }, "azure-security-keyvault-administration-cpp": { "baseline": "4.0.0-beta.5", @@ -498,22 +498,22 @@ }, "azure-security-keyvault-certificates-cpp": { "baseline": "4.2.1", - "port-version": 1 + "port-version": 2 }, "azure-security-keyvault-keys-cpp": { "baseline": "4.4.1", - "port-version": 1 + "port-version": 2 }, "azure-security-keyvault-secrets-cpp": { "baseline": "4.2.1", - "port-version": 1 + "port-version": 2 }, "azure-storage-blobs-cpp": { - "baseline": "12.12.0", + "baseline": "12.13.0", "port-version": 0 }, "azure-storage-common-cpp": { - "baseline": "12.7.0", + "baseline": "12.8.0", "port-version": 0 }, "azure-storage-cpp": { @@ -521,15 +521,15 @@ "port-version": 6 }, "azure-storage-files-datalake-cpp": { - "baseline": "12.11.0", + "baseline": "12.12.0", "port-version": 0 }, "azure-storage-files-shares-cpp": { - "baseline": "12.10.0", + "baseline": "12.11.0", "port-version": 0 }, "azure-storage-queues-cpp": { - "baseline": "12.3.0", + "baseline": "12.4.0", "port-version": 0 }, "azure-uamqp-c": { @@ -569,8 +569,8 @@ "port-version": 0 }, "bde": { - "baseline": "4.8.0.0", - "port-version": 1 + "baseline": "4.14.0.0", + "port-version": 0 }, "bdwgc": { "baseline": "8.2.8", @@ -648,6 +648,10 @@ "baseline": "3.0", "port-version": 3 }, + "bit7z": { + "baseline": "4.0.8", + "port-version": 0 + }, "bitmagic": { "baseline": "7.13.4", "port-version": 0 @@ -705,7 +709,7 @@ "port-version": 0 }, "blosc": { - "baseline": "1.21.5", + "baseline": "1.21.6", "port-version": 0 }, "blpapi": { @@ -721,8 +725,8 @@ "port-version": 0 }, "bond": { - "baseline": "11.0.1", - "port-version": 4 + "baseline": "13.0.1", + "port-version": 0 }, "boolinq": { "baseline": "3.0.4", @@ -1234,7 +1238,7 @@ }, "boost-stacktrace": { "baseline": "1.85.0", - "port-version": 3 + "port-version": 4 }, "boost-statechart": { "baseline": "1.85.0", @@ -1361,7 +1365,7 @@ "port-version": 1 }, "boringssl": { - "baseline": "2023-10-13", + "baseline": "2024-09-13", "port-version": 0 }, "botan": { @@ -1409,7 +1413,7 @@ "port-version": 0 }, "buck-yeh-bux": { - "baseline": "1.8.0", + "baseline": "1.8.1", "port-version": 0 }, "buck-yeh-bux-mariadb-client": { @@ -1445,7 +1449,7 @@ "port-version": 6 }, "c-ares": { - "baseline": "1.33.1", + "baseline": "1.34.1", "port-version": 0 }, "c-dbg-macro": { @@ -1472,10 +1476,6 @@ "baseline": "1.0.1", "port-version": 0 }, - "caffe2": { - "baseline": "0.8.1", - "port-version": 8 - }, "cairo": { "baseline": "1.18.0", "port-version": 1 @@ -1485,7 +1485,7 @@ "port-version": 0 }, "calceph": { - "baseline": "4.0.0", + "baseline": "4.0.1", "port-version": 0 }, "camport3": { @@ -1581,8 +1581,8 @@ "port-version": 6 }, "cgal": { - "baseline": "5.6.1", - "port-version": 1 + "baseline": "6.0", + "port-version": 0 }, "cgicc": { "baseline": "3.2.20", @@ -1669,7 +1669,7 @@ "port-version": 0 }, "clap-cleveraudio": { - "baseline": "1.2.0", + "baseline": "1.2.2", "port-version": 0 }, "clapack": { @@ -1685,7 +1685,7 @@ "port-version": 7 }, "clblast": { - "baseline": "1.6.1", + "baseline": "1.6.3", "port-version": 0 }, "cld3": { @@ -1737,7 +1737,7 @@ "port-version": 0 }, "cmark": { - "baseline": "0.30.3", + "baseline": "0.31.1", "port-version": 0 }, "cminpack": { @@ -1925,7 +1925,7 @@ "port-version": 0 }, "cppad": { - "baseline": "20240000.6", + "baseline": "20240000.7", "port-version": 0 }, "cppcms": { @@ -1985,7 +1985,7 @@ "port-version": 4 }, "cpptrace": { - "baseline": "0.7.1", + "baseline": "0.7.2", "port-version": 0 }, "cppunit": { @@ -2157,11 +2157,11 @@ "port-version": 0 }, "cyclonedds": { - "baseline": "0.10.4", + "baseline": "0.10.5", "port-version": 0 }, "cyclonedds-cxx": { - "baseline": "0.10.4", + "baseline": "0.10.5", "port-version": 0 }, "cyrus-sasl": { @@ -2193,7 +2193,7 @@ "port-version": 3 }, "dataframe": { - "baseline": "3.2.0", + "baseline": "3.3.0", "port-version": 0 }, "date": { @@ -2221,8 +2221,8 @@ "port-version": 0 }, "daxa": { - "baseline": "2.0.0", - "port-version": 0 + "baseline": "3.0.2", + "port-version": 1 }, "dbg-macro": { "baseline": "0.5.1", @@ -2269,7 +2269,7 @@ "port-version": 13 }, "dimcli": { - "baseline": "7.2.0", + "baseline": "7.3.0", "port-version": 0 }, "dingo": { @@ -2278,7 +2278,7 @@ }, "directx-dxc": { "baseline": "2024-07-31", - "port-version": 0 + "port-version": 1 }, "directx-headers": { "baseline": "1.614.1", @@ -2329,7 +2329,7 @@ "port-version": 0 }, "discount": { - "baseline": "3.0.0a", + "baseline": "3.0.0d", "port-version": 0 }, "discreture": { @@ -2377,7 +2377,7 @@ "port-version": 0 }, "dpp": { - "baseline": "10.0.31", + "baseline": "10.0.32", "port-version": 0 }, "draco": { @@ -2437,8 +2437,8 @@ "port-version": 7 }, "dxut": { - "baseline": "11.31", - "port-version": 3 + "baseline": "11.32", + "port-version": 0 }, "dylib": { "baseline": "2.2.1", @@ -2557,7 +2557,7 @@ "port-version": 3 }, "ensmallen": { - "baseline": "2.19.1", + "baseline": "2.21.1", "port-version": 0 }, "entityx": { @@ -2585,8 +2585,8 @@ "port-version": 0 }, "etl": { - "baseline": "20.38.10", - "port-version": 1 + "baseline": "20.39.4", + "port-version": 0 }, "eve": { "baseline": "2023.2.15", @@ -2602,7 +2602,7 @@ }, "exiv2": { "baseline": "0.28.3", - "port-version": 1 + "port-version": 2 }, "expat": { "baseline": "2.6.3", @@ -2665,13 +2665,17 @@ "port-version": 0 }, "fastcdr": { - "baseline": "2.2.1", + "baseline": "2.2.4", "port-version": 0 }, "fastcgi": { "baseline": "2020-09-11", "port-version": 5 }, + "fastdds": { + "baseline": "3.0.1", + "port-version": 0 + }, "fastfeat": { "baseline": "391d5e9", "port-version": 4 @@ -2692,12 +2696,8 @@ "baseline": "2021-11-22", "port-version": 1 }, - "fastrtps": { - "baseline": "2.14.0", - "port-version": 0 - }, "faudio": { - "baseline": "24.06", + "baseline": "24.09", "port-version": 0 }, "fawdlstty-libfv": { @@ -2709,7 +2709,7 @@ "port-version": 1 }, "fbthrift": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "fcl": { @@ -2757,7 +2757,7 @@ "port-version": 0 }, "fizz": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "flagpp": { @@ -2801,7 +2801,7 @@ "port-version": 0 }, "flecs": { - "baseline": "4.0.1", + "baseline": "4.0.2", "port-version": 0 }, "flint": { @@ -2838,10 +2838,10 @@ }, "fmt": { "baseline": "11.0.2", - "port-version": 0 + "port-version": 1 }, "folly": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "font-chef": { @@ -2854,7 +2854,7 @@ }, "fontconfig": { "baseline": "2.15.0", - "port-version": 0 + "port-version": 1 }, "foonathan-lexy": { "baseline": "2022.12.1", @@ -2913,7 +2913,7 @@ "port-version": 0 }, "fribidi": { - "baseline": "1.0.15", + "baseline": "1.0.16", "port-version": 0 }, "frozen": { @@ -2921,8 +2921,8 @@ "port-version": 0 }, "frugally-deep": { - "baseline": "0.15.31", - "port-version": 1 + "baseline": "0.16.0", + "port-version": 0 }, "fruit": { "baseline": "3.7.1", @@ -3001,7 +3001,7 @@ "port-version": 5 }, "gcem": { - "baseline": "1.17.0", + "baseline": "1.18.0", "port-version": 0 }, "gdal": { @@ -3037,7 +3037,7 @@ "port-version": 0 }, "geos": { - "baseline": "3.12.2", + "baseline": "3.13.0", "port-version": 0 }, "geotrans": { @@ -3105,7 +3105,7 @@ "port-version": 0 }, "glaze": { - "baseline": "3.4.0", + "baseline": "3.6.1", "port-version": 0 }, "glbinding": { @@ -3125,8 +3125,8 @@ "port-version": 2 }, "glib": { - "baseline": "2.78.4", - "port-version": 3 + "baseline": "2.80.0", + "port-version": 0 }, "glib-networking": { "baseline": "2.78.0", @@ -3149,8 +3149,8 @@ "port-version": 0 }, "gloo": { - "baseline": "20201203", - "port-version": 3 + "baseline": "20240626", + "port-version": 0 }, "glpk": { "baseline": "5.0", @@ -3169,7 +3169,7 @@ "port-version": 6 }, "gmmlib": { - "baseline": "22.3.20", + "baseline": "22.5.2", "port-version": 0 }, "gmp": { @@ -3185,11 +3185,11 @@ "port-version": 8 }, "godot-cpp": { - "baseline": "4.2.1", + "baseline": "4.3", "port-version": 0 }, "google-cloud-cpp": { - "baseline": "2.29.0", + "baseline": "2.30.0", "port-version": 0 }, "google-cloud-cpp-common": { @@ -3297,7 +3297,7 @@ "port-version": 0 }, "gtl": { - "baseline": "1.1.8", + "baseline": "1.2.0", "port-version": 0 }, "gts": { @@ -3313,8 +3313,8 @@ "port-version": 2 }, "guile": { - "baseline": "3.0.9", - "port-version": 1 + "baseline": "3.0.10", + "port-version": 0 }, "guilite": { "baseline": "2022-05-05", @@ -3409,7 +3409,7 @@ "port-version": 0 }, "harfbuzz": { - "baseline": "9.0.0", + "baseline": "10.0.1", "port-version": 0 }, "hash-library": { @@ -3489,7 +3489,7 @@ "port-version": 0 }, "hlslpp": { - "baseline": "3.5", + "baseline": "3.5.3", "port-version": 0 }, "hnswlib": { @@ -3525,8 +3525,8 @@ "port-version": 1 }, "hwloc": { - "baseline": "2.10.0", - "port-version": 1 + "baseline": "2.11.2", + "port-version": 0 }, "hyperscan": { "baseline": "5.4.2", @@ -3541,7 +3541,7 @@ "port-version": 1 }, "iceoryx": { - "baseline": "2.0.5", + "baseline": "2.0.6", "port-version": 0 }, "icu": { @@ -3645,7 +3645,7 @@ "port-version": 0 }, "iir1": { - "baseline": "1.9.4", + "baseline": "1.9.5", "port-version": 0 }, "ijg-libjpeg": { @@ -3661,7 +3661,7 @@ "port-version": 0 }, "imath": { - "baseline": "3.1.11", + "baseline": "3.1.12", "port-version": 0 }, "imcce-openfa": { @@ -3757,7 +3757,7 @@ "port-version": 0 }, "ismrmrd": { - "baseline": "1.13.7", + "baseline": "1.14.1", "port-version": 0 }, "itay-grudev-singleapplication": { @@ -3793,7 +3793,7 @@ "port-version": 1 }, "jasper": { - "baseline": "4.2.1", + "baseline": "4.2.4", "port-version": 0 }, "jbig2dec": { @@ -3862,15 +3862,15 @@ }, "json5-parser": { "baseline": "1.0.0", - "port-version": 6 + "port-version": 7 }, "jsoncons": { "baseline": "0.177.0", "port-version": 0 }, "jsoncpp": { - "baseline": "1.9.5", - "port-version": 5 + "baseline": "1.9.6", + "port-version": 0 }, "jsonifier": { "baseline": "0.9.96", @@ -3886,7 +3886,7 @@ }, "jwt-cpp": { "baseline": "0.7.0", - "port-version": 0 + "port-version": 1 }, "jxrlib": { "baseline": "2019.10.9", @@ -3909,7 +3909,7 @@ "port-version": 0 }, "kdbindings": { - "baseline": "1.0.3", + "baseline": "1.0.5", "port-version": 0 }, "kddockwidgets": { @@ -4217,7 +4217,7 @@ "port-version": 0 }, "level-zero": { - "baseline": "1.17.28", + "baseline": "1.17.45", "port-version": 0 }, "leveldb": { @@ -4273,7 +4273,7 @@ "port-version": 5 }, "libarchive": { - "baseline": "3.7.5", + "baseline": "3.7.6", "port-version": 0 }, "libass": { @@ -4302,14 +4302,14 @@ }, "libbacktrace": { "baseline": "2023-11-30", - "port-version": 0 + "port-version": 1 }, "libbf": { "baseline": "1.0.0", "port-version": 4 }, "libbson": { - "baseline": "1.28.0", + "baseline": "1.28.1", "port-version": 0 }, "libcaer": { @@ -4368,6 +4368,10 @@ "baseline": "1.0", "port-version": 2 }, + "libcred": { + "baseline": "1.0.0", + "port-version": 0 + }, "libcroco": { "baseline": "0.6.13", "port-version": 7 @@ -4401,7 +4405,7 @@ "port-version": 0 }, "libdeflate": { - "baseline": "1.21", + "baseline": "1.22", "port-version": 0 }, "libdisasm": { @@ -4413,7 +4417,7 @@ "port-version": 0 }, "libdjinterop": { - "baseline": "0.21.0", + "baseline": "0.22.1", "port-version": 0 }, "libdmx": { @@ -4453,7 +4457,7 @@ "port-version": 2 }, "liberasurecode": { - "baseline": "1.6.3", + "baseline": "1.6.4", "port-version": 0 }, "libev": { @@ -4565,7 +4569,7 @@ "port-version": 0 }, "libgpiod": { - "baseline": "2.1.2", + "baseline": "2.1.3", "port-version": 0 }, "libgpod": { @@ -4605,7 +4609,7 @@ "port-version": 0 }, "libhv": { - "baseline": "1.3.2", + "baseline": "1.3.3", "port-version": 0 }, "libhydrogen": { @@ -4613,7 +4617,7 @@ "port-version": 0 }, "libical": { - "baseline": "3.0.17", + "baseline": "3.0.18", "port-version": 0 }, "libice": { @@ -4625,7 +4629,7 @@ "port-version": 4 }, "libics": { - "baseline": "1.6.6", + "baseline": "1.6.8", "port-version": 0 }, "libid3tag": { @@ -4665,7 +4669,7 @@ "port-version": 0 }, "libjuice": { - "baseline": "1.5.2", + "baseline": "1.5.4", "port-version": 0 }, "libjxl": { @@ -4721,7 +4725,7 @@ "port-version": 1 }, "liblzma": { - "baseline": "5.6.2", + "baseline": "5.6.3", "port-version": 0 }, "libmad": { @@ -4733,11 +4737,11 @@ "port-version": 3 }, "libmariadb": { - "baseline": "3.3.1", - "port-version": 4 + "baseline": "3.4.1", + "port-version": 0 }, "libmaxminddb": { - "baseline": "1.9.1", + "baseline": "1.11.0", "port-version": 0 }, "libmediainfo": { @@ -4757,7 +4761,7 @@ "port-version": 1 }, "libmidi2": { - "baseline": "0.11", + "baseline": "0.13", "port-version": 0 }, "libmikmod": { @@ -4800,17 +4804,21 @@ "baseline": "1.23.11", "port-version": 0 }, + "libmysofa": { + "baseline": "1.3.2", + "port-version": 0 + }, "libmysql": { "baseline": "8.0.39", "port-version": 0 }, "libnice": { - "baseline": "0.1.21", - "port-version": 2 + "baseline": "0.1.22", + "port-version": 0 }, "libnice-gst": { - "baseline": "0.1.21", - "port-version": 4 + "baseline": "0.1.22", + "port-version": 0 }, "libnick": { "baseline": "2024.9.2", @@ -4857,8 +4865,8 @@ "port-version": 1 }, "libopenmpt": { - "baseline": "0.7.4", - "port-version": 1 + "baseline": "0.7.10", + "port-version": 0 }, "libopensp": { "baseline": "1.5.2", @@ -4901,8 +4909,8 @@ "port-version": 5 }, "libpcap": { - "baseline": "1.10.4", - "port-version": 1 + "baseline": "1.10.5", + "port-version": 0 }, "libpff": { "baseline": "2021-11-14", @@ -4969,16 +4977,16 @@ "port-version": 0 }, "libraqm": { - "baseline": "0.10.1", + "baseline": "0.10.2", "port-version": 0 }, "libraw": { - "baseline": "0.21.2", + "baseline": "0.21.3", "port-version": 0 }, "librdkafka": { - "baseline": "2.3.0", - "port-version": 5 + "baseline": "2.6.0", + "port-version": 0 }, "libredwg": { "baseline": "0.13.3", @@ -4990,7 +4998,7 @@ }, "libressl": { "baseline": "3.9.2", - "port-version": 1 + "port-version": 2 }, "librsvg": { "baseline": "2.40.20", @@ -5081,8 +5089,8 @@ "port-version": 7 }, "libsoup": { - "baseline": "3.4.4", - "port-version": 1 + "baseline": "3.6.0", + "port-version": 0 }, "libspatialindex": { "baseline": "1.9.3", @@ -5106,7 +5114,7 @@ }, "libsrt": { "baseline": "1.5.3", - "port-version": 2 + "port-version": 3 }, "libsrtp": { "baseline": "2.5.0", @@ -5129,8 +5137,8 @@ "port-version": 3 }, "libsvm": { - "baseline": "3.32", - "port-version": 1 + "baseline": "3.35", + "port-version": 0 }, "libsystemd": { "baseline": "256.4", @@ -5165,7 +5173,7 @@ "port-version": 3 }, "libtommath": { - "baseline": "1.2.1", + "baseline": "1.3.0", "port-version": 0 }, "libtorch": { @@ -5218,7 +5226,7 @@ }, "libunwind": { "baseline": "1.8.1", - "port-version": 0 + "port-version": 1 }, "liburing": { "baseline": "2.7", @@ -5245,21 +5253,25 @@ "port-version": 14 }, "libuv": { - "baseline": "1.48.0", - "port-version": 1 + "baseline": "1.49.0", + "port-version": 0 }, "libuvc": { "baseline": "0.0.7", "port-version": 1 }, "libvault": { - "baseline": "0.56.0", + "baseline": "0.61.0", "port-version": 0 }, "libvhdi": { "baseline": "20231127", "port-version": 0 }, + "libvmaf": { + "baseline": "3.0.0", + "port-version": 0 + }, "libvmdk": { "baseline": "20221124", "port-version": 1 @@ -5361,8 +5373,8 @@ "port-version": 0 }, "libxlsxwriter": { - "baseline": "1.1.5", - "port-version": 2 + "baseline": "1.1.8", + "port-version": 1 }, "libxml2": { "baseline": "2.11.9", @@ -5385,8 +5397,8 @@ "port-version": 1 }, "libxpm": { - "baseline": "3.5.16", - "port-version": 1 + "baseline": "3.5.17", + "port-version": 0 }, "libxpresent": { "baseline": "1.0.0", @@ -5433,7 +5445,7 @@ "port-version": 5 }, "libyuv": { - "baseline": "1895", + "baseline": "1896", "port-version": 1 }, "libzen": { @@ -5457,8 +5469,8 @@ "port-version": 0 }, "lightgbm": { - "baseline": "4.4.0", - "port-version": 1 + "baseline": "4.5.0", + "port-version": 0 }, "lightningscanner": { "baseline": "1.0.1", @@ -5485,7 +5497,7 @@ "port-version": 0 }, "live555": { - "baseline": "2024-06-26", + "baseline": "2024-09-29", "port-version": 0 }, "llfio": { @@ -5501,7 +5513,7 @@ "port-version": 0 }, "llhttp": { - "baseline": "9.2.0", + "baseline": "9.2.1", "port-version": 0 }, "llnl-units": { @@ -5549,8 +5561,8 @@ "port-version": 1 }, "ls-qpack": { - "baseline": "2.5.4", - "port-version": 3 + "baseline": "2.5.5", + "port-version": 0 }, "ltla-aarand": { "baseline": "2023-03-19", @@ -5594,7 +5606,7 @@ }, "luafilesystem": { "baseline": "1.8.0", - "port-version": 6 + "port-version": 7 }, "luajit": { "baseline": "2023-01-04", @@ -5633,7 +5645,7 @@ "port-version": 0 }, "lzav": { - "baseline": "3.13", + "baseline": "4.0", "port-version": 0 }, "lzfse": { @@ -5662,7 +5674,7 @@ }, "magma": { "baseline": "2.8.0", - "port-version": 0 + "port-version": 1 }, "magnum": { "baseline": "2020.06", @@ -5721,7 +5733,7 @@ "port-version": 0 }, "marble": { - "baseline": "24.07.90", + "baseline": "24.08.2", "port-version": 0 }, "mariadb-connector-cpp": { @@ -5741,7 +5753,7 @@ "port-version": 0 }, "materialx": { - "baseline": "1.38.9", + "baseline": "1.39.1", "port-version": 0 }, "mathc": { @@ -5757,7 +5769,7 @@ "port-version": 0 }, "matio": { - "baseline": "1.5.26", + "baseline": "1.5.27", "port-version": 0 }, "matplotlib-cpp": { @@ -5957,12 +5969,12 @@ "port-version": 2 }, "mongo-c-driver": { - "baseline": "1.28.0", + "baseline": "1.28.1", "port-version": 0 }, "mongo-cxx-driver": { - "baseline": "3.10.2", - "port-version": 1 + "baseline": "3.11.0", + "port-version": 0 }, "mongoose": { "baseline": "7.15", @@ -5997,7 +6009,7 @@ "port-version": 1 }, "mp-units": { - "baseline": "2.2.1", + "baseline": "2.3.0", "port-version": 0 }, "mp3lame": { @@ -6078,7 +6090,7 @@ }, "msh3": { "baseline": "0.6.0", - "port-version": 0 + "port-version": 1 }, "msinttypes": { "baseline": "2018-02-25", @@ -6093,8 +6105,8 @@ "port-version": 4 }, "msquic": { - "baseline": "2.3.6", - "port-version": 2 + "baseline": "2.4.5", + "port-version": 1 }, "mstch": { "baseline": "1.0.2", @@ -6129,7 +6141,7 @@ "port-version": 7 }, "mvfst": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "mygui": { @@ -6181,8 +6193,8 @@ "port-version": 2 }, "nanopb": { - "baseline": "0.4.8", - "port-version": 1 + "baseline": "0.4.9", + "port-version": 0 }, "nanoprintf": { "baseline": "0.3.4", @@ -6205,7 +6217,7 @@ "port-version": 6 }, "nativefiledialog-extended": { - "baseline": "1.2.0", + "baseline": "1.2.1", "port-version": 0 }, "nayuki-qr-code-generator": { @@ -6277,8 +6289,8 @@ "port-version": 1 }, "nghttp3": { - "baseline": "1.5.0", - "port-version": 1 + "baseline": "1.6.0", + "port-version": 0 }, "ngspice": { "baseline": "41", @@ -6310,7 +6322,7 @@ }, "nmap": { "baseline": "7.70", - "port-version": 11 + "port-version": 12 }, "nmslib": { "baseline": "2.1.1", @@ -6361,7 +6373,7 @@ "port-version": 1 }, "nsync": { - "baseline": "1.26.0", + "baseline": "1.29.2", "port-version": 0 }, "nt-wrapper": { @@ -6389,7 +6401,7 @@ "port-version": 2 }, "nuspell": { - "baseline": "5.1.4", + "baseline": "5.1.6", "port-version": 0 }, "nvidia-cutlass": { @@ -6477,8 +6489,8 @@ "port-version": 0 }, "ode": { - "baseline": "0.16.4", - "port-version": 1 + "baseline": "0.16.5", + "port-version": 0 }, "offscale-libetcd-cpp": { "baseline": "2019-07-10", @@ -6545,7 +6557,7 @@ "port-version": 0 }, "open62541pp": { - "baseline": "0.14.0", + "baseline": "0.15.0", "port-version": 0 }, "openal-soft": { @@ -6634,7 +6646,7 @@ }, "openimageio": { "baseline": "2.5.14.0", - "port-version": 0 + "port-version": 1 }, "openjpeg": { "baseline": "2.5.2", @@ -6717,7 +6729,7 @@ "port-version": 0 }, "openvino": { - "baseline": "2024.3.0", + "baseline": "2024.4.0", "port-version": 0 }, "openvpn3": { @@ -6821,7 +6833,7 @@ "port-version": 3 }, "parallel-hashmap": { - "baseline": "1.3.12", + "baseline": "1.4.0", "port-version": 0 }, "parallelstl": { @@ -6845,7 +6857,7 @@ "port-version": 0 }, "parson": { - "baseline": "2022-11-13", + "baseline": "2023-10-31", "port-version": 0 }, "pbc": { @@ -7049,7 +7061,7 @@ "port-version": 0 }, "podofo": { - "baseline": "0.10.3", + "baseline": "0.10.4", "port-version": 0 }, "poissonrecon": { @@ -7177,7 +7189,7 @@ "port-version": 0 }, "proxygen": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "psimd": { @@ -7222,7 +7234,7 @@ }, "pulseaudio": { "baseline": "17.0", - "port-version": 1 + "port-version": 2 }, "pulzed-mini": { "baseline": "0.9.14", @@ -7242,7 +7254,7 @@ }, "python3": { "baseline": "3.11.8", - "port-version": 4 + "port-version": 5 }, "qca": { "baseline": "2.3.7", @@ -7285,7 +7297,7 @@ "port-version": 1 }, "qt": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qt-advanced-docking-system": { @@ -7293,7 +7305,7 @@ "port-version": 0 }, "qt3d": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qt5": { @@ -7469,67 +7481,67 @@ "port-version": 0 }, "qt5compat": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtactiveqt": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtapplicationmanager": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtbase": { - "baseline": "6.7.2", - "port-version": 3 + "baseline": "6.7.3", + "port-version": 0 }, "qtcharts": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtcoap": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtconnectivity": { - "baseline": "6.7.2", - "port-version": 1 + "baseline": "6.7.3", + "port-version": 0 }, "qtdatavis3d": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtdeclarative": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtdeviceutilities": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtdoc": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtgraphs": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtgrpc": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qthttpserver": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtimageformats": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtinterfaceframework": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtkeychain": { @@ -7541,43 +7553,43 @@ "port-version": 0 }, "qtlanguageserver": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtlocation": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtlottie": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtmqtt": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtmultimedia": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtnetworkauth": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtopcua": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtpositioning": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtquick3d": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtquick3dphysics": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtquickcontrols2": { @@ -7585,75 +7597,75 @@ "port-version": 1 }, "qtquickeffectmaker": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtquicktimeline": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtremoteobjects": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtscxml": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtsensors": { - "baseline": "6.7.2", - "port-version": 1 + "baseline": "6.7.3", + "port-version": 0 }, "qtserialbus": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtserialport": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtshadertools": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtspeech": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtsvg": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qttools": { - "baseline": "6.7.2", - "port-version": 1 + "baseline": "6.7.3", + "port-version": 0 }, "qttranslations": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtvirtualkeyboard": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtwayland": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtwebchannel": { - "baseline": "6.7.2", - "port-version": 1 + "baseline": "6.7.3", + "port-version": 0 }, "qtwebengine": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtwebsockets": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "qtwebview": { - "baseline": "6.7.2", + "baseline": "6.7.3", "port-version": 0 }, "quadtree": { @@ -7681,7 +7693,7 @@ "port-version": 9 }, "quill": { - "baseline": "7.1.0", + "baseline": "7.3.0", "port-version": 0 }, "quirc": { @@ -7762,7 +7774,7 @@ }, "raylib": { "baseline": "5.0", - "port-version": 1 + "port-version": 2 }, "rbdl": { "baseline": "3.3.0", @@ -7810,7 +7822,7 @@ }, "realsense2": { "baseline": "2.54.2", - "port-version": 2 + "port-version": 3 }, "recast": { "baseline": "deprecated", @@ -7921,7 +7933,7 @@ "port-version": 0 }, "robotraconteur": { - "baseline": "1.2.2", + "baseline": "1.2.3", "port-version": 0 }, "robotraconteur-companion": { @@ -7996,6 +8008,10 @@ "baseline": "3.3.0", "port-version": 1 }, + "ruckig": { + "baseline": "0.14.0", + "port-version": 0 + }, "rxcpp": { "baseline": "4.1.1", "port-version": 1 @@ -8029,8 +8045,8 @@ "port-version": 0 }, "sail": { - "baseline": "0.9.5", - "port-version": 1 + "baseline": "0.9.6", + "port-version": 0 }, "sajson": { "baseline": "2018-09-21", @@ -8133,7 +8149,7 @@ "port-version": 6 }, "sdl2": { - "baseline": "2.30.7", + "baseline": "2.30.8", "port-version": 0 }, "sdl2-gfx": { @@ -8189,7 +8205,7 @@ "port-version": 0 }, "sentry-native": { - "baseline": "0.7.9", + "baseline": "0.7.10", "port-version": 0 }, "septag-dmon": { @@ -8213,7 +8229,7 @@ "port-version": 0 }, "sese": { - "baseline": "2.2.0", + "baseline": "2.3.0", "port-version": 1 }, "sf2cute": { @@ -8325,7 +8341,7 @@ "port-version": 0 }, "simsimd": { - "baseline": "5.4.1", + "baseline": "5.4.4", "port-version": 0 }, "sjpeg": { @@ -8338,7 +8354,7 @@ }, "skia": { "baseline": "129", - "port-version": 0 + "port-version": 1 }, "skyr-url": { "baseline": "1.13.0", @@ -8380,10 +8396,6 @@ "baseline": "1.2.1", "port-version": 0 }, - "sndfile": { - "baseline": "0", - "port-version": 2 - }, "snitch": { "baseline": "1.2.5", "port-version": 0 @@ -8553,7 +8565,7 @@ "port-version": 3 }, "sqlcipher": { - "baseline": "4.6.0", + "baseline": "4.6.1", "port-version": 0 }, "sqlite-modern-cpp": { @@ -8574,7 +8586,7 @@ }, "sqlpp11": { "baseline": "0.64", - "port-version": 0 + "port-version": 2 }, "sqlpp11-connector-mysql": { "baseline": "0.61", @@ -8693,7 +8705,7 @@ "port-version": 2 }, "sundials": { - "baseline": "6.2.0", + "baseline": "7.1.1", "port-version": 0 }, "superlu": { @@ -8745,7 +8757,7 @@ "port-version": 0 }, "taskflow": { - "baseline": "3.7.0", + "baseline": "3.8.0", "port-version": 0 }, "tbb": { @@ -8822,7 +8834,7 @@ }, "theia": { "baseline": "0.8", - "port-version": 10 + "port-version": 11 }, "think-cell-range": { "baseline": "2023.1", @@ -8850,7 +8862,7 @@ }, "tidy-html5": { "baseline": "5.8.0", - "port-version": 1 + "port-version": 2 }, "tiff": { "baseline": "4.6.0", @@ -9049,7 +9061,7 @@ "port-version": 0 }, "trompeloeil": { - "baseline": "47", + "baseline": "48", "port-version": 0 }, "try-catcher": { @@ -9160,10 +9172,6 @@ "baseline": "1.1.1", "port-version": 0 }, - "urho3d": { - "baseline": "2021-03-01", - "port-version": 5 - }, "uriparser": { "baseline": "0.9.8", "port-version": 0 @@ -9225,7 +9233,7 @@ "port-version": 0 }, "uwebsockets": { - "baseline": "20.65.0", + "baseline": "20.67.0", "port-version": 0 }, "v-hacd": { @@ -9273,11 +9281,11 @@ "port-version": 0 }, "vcpkg-cmake-get-vars": { - "baseline": "2023-12-31", + "baseline": "2024-09-22", "port-version": 0 }, "vcpkg-get-python": { - "baseline": "2024-06-08", + "baseline": "2024-06-22", "port-version": 0 }, "vcpkg-get-python-packages": { @@ -9321,7 +9329,7 @@ "port-version": 1 }, "vcpkg-tool-meson": { - "baseline": "1.5.1", + "baseline": "1.5.2", "port-version": 0 }, "vcpkg-tool-mozbuild": { @@ -9425,8 +9433,8 @@ "port-version": 5 }, "vtk-dicom": { - "baseline": "0.8.14", - "port-version": 2 + "baseline": "0.8.16", + "port-version": 0 }, "vtk-m": { "baseline": "2.1.0", @@ -9478,7 +9486,7 @@ }, "vxl": { "baseline": "2.0.2", - "port-version": 6 + "port-version": 7 }, "wabt": { "baseline": "1.0.36", @@ -9489,7 +9497,7 @@ "port-version": 5 }, "wangle": { - "baseline": "2024.09.16.00", + "baseline": "2024.09.30.00", "port-version": 0 }, "wasmedge": { @@ -9501,8 +9509,8 @@ "port-version": 0 }, "wavpack": { - "baseline": "5.6.0", - "port-version": 2 + "baseline": "5.7.0", + "port-version": 0 }, "wayland": { "baseline": "1.21.0", @@ -9577,7 +9585,7 @@ "port-version": 0 }, "wmipp": { - "baseline": "1.2.0", + "baseline": "1.3.0", "port-version": 0 }, "woff2": { @@ -9629,8 +9637,8 @@ "port-version": 0 }, "wxwidgets": { - "baseline": "3.2.5", - "port-version": 3 + "baseline": "3.2.6", + "port-version": 0 }, "wyhash": { "baseline": "2023-12-03", @@ -9665,7 +9673,7 @@ "port-version": 0 }, "xbyak": { - "baseline": "7.6", + "baseline": "7.7", "port-version": 0 }, "xcb": { @@ -9833,7 +9841,7 @@ "port-version": 0 }, "z3": { - "baseline": "4.13.0", + "baseline": "4.13.3", "port-version": 0 }, "z4kn4fein-semver": { @@ -9877,8 +9885,8 @@ "port-version": 1 }, "zlmediakit": { - "baseline": "2024-03-30", - "port-version": 3 + "baseline": "2024-09-29", + "port-version": 0 }, "zoe": { "baseline": "3.1", diff --git a/vcpkg/versions/d-/dpp.json b/vcpkg/versions/d-/dpp.json index a9e40299c5..05a8f382d5 100644 --- a/vcpkg/versions/d-/dpp.json +++ b/vcpkg/versions/d-/dpp.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "7543dc1ca437d9f26cb6754b9f60ff58901c0e2a", + "version": "10.0.32", + "port-version": 0 + }, { "git-tree": "190a206eddf272472a4668d756e0293096341f97", "version": "10.0.31", From 7940773c3e6a846f24c80841096040c9bc4d3cbf Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Sun, 13 Oct 2024 12:20:43 +0100 Subject: [PATCH 69/99] fix: vcpkg is always built with voice (#1272) --- library-vcpkg/CMakeLists.txt | 37 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/library-vcpkg/CMakeLists.txt b/library-vcpkg/CMakeLists.txt index 3148b6163d..16df61f4f5 100644 --- a/library-vcpkg/CMakeLists.txt +++ b/library-vcpkg/CMakeLists.txt @@ -18,12 +18,7 @@ add_compile_definitions(HAVE_VOICE) -if (HAVE_VOICE) - file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/enabled/*.cpp" "${DPP_ROOT_PATH}/dpp/dave/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") -else() - file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/stub/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") -endif() - +file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/enabled/*.cpp" "${DPP_ROOT_PATH}/dpp/dave/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") set(LIB_NAME "${PROJECT_NAME}") @@ -87,12 +82,10 @@ target_include_directories( "$" ) -if (HAVE_VOICE) - add_subdirectory("${DPP_ROOT_PATH}/mlspp" "mlspp") - include_directories("${DPP_ROOT_PATH}/mlspp/include") - include_directories("${DPP_ROOT_PATH}/mlspp/lib/bytes/include") - include_directories("${DPP_ROOT_PATH}/mlspp/lib/hpke/include") -endif() +add_subdirectory("${DPP_ROOT_PATH}/mlspp" "mlspp") +include_directories("${DPP_ROOT_PATH}/mlspp/include") +include_directories("${DPP_ROOT_PATH}/mlspp/lib/bytes/include") +include_directories("${DPP_ROOT_PATH}/mlspp/lib/hpke/include") set_target_properties( "${LIB_NAME}" PROPERTIES @@ -120,17 +113,15 @@ target_link_libraries( $<$:Threads::Threads> ) -if (HAVE_VOICE) - # Private statically linked dependencies - target_link_libraries( - ${LIB_NAME} PRIVATE - mlspp - mls_vectors - bytes - tls_syntax - hpke - ) -endif() +# Private statically linked dependencies +target_link_libraries( + ${LIB_NAME} PRIVATE + mlspp + mls_vectors + bytes + tls_syntax + hpke +) set(CONFIG_FILE_NAME "${PROJECT_NAME}Config.cmake") set(EXPORTED_TARGETS_NAME "${PROJECT_NAME}Targets") From 6ba5df850f2b57363a18bee9b85da555fc3341dc Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Sun, 13 Oct 2024 19:52:42 +0000 Subject: [PATCH 70/99] [skip ci] version bump --- include/dpp/version.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/dpp/version.h b/include/dpp/version.h index d047704e86..e94dc4af7b 100644 --- a/include/dpp/version.h +++ b/include/dpp/version.h @@ -21,10 +21,10 @@ ************************************************************************************/ #pragma once -#if !defined(DPP_VERSION_LONG) -#define DPP_VERSION_LONG 0x00100032 -#define DPP_VERSION_SHORT 100032 -#define DPP_VERSION_TEXT "D++ 10.0.32 (22-Sep-2024)" +#ifndef DPP_VERSION_LONG +#define DPP_VERSION_LONG 0x00100033 +#define DPP_VERSION_SHORT 100033 +#define DPP_VERSION_TEXT "D++ 10.0.33 (13-Oct-2024)" #define DPP_VERSION_MAJOR ((DPP_VERSION_LONG & 0x00ff0000) >> 16) #define DPP_VERSION_MINOR ((DPP_VERSION_LONG & 0x0000ff00) >> 8) From 16cbfd009f3e882b2ca2cecbb3a9707864fced68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:47:07 +0100 Subject: [PATCH 71/99] build(deps): bump ubuntu from `b359f10` to `ab64a83` (#1278) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5ae726414a..e0f58b293f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:b359f1067efa76f37863778f7b6d0e8d911e3ee8efa807ad01fbf5dc1ef9006b +FROM ubuntu:noble@sha256:ab64a8382e935382638764d8719362bb50ee418d944c1f3d26e0c99fae49a345 RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From dc2005914059f407b35b446865f0db49974b2b0e Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Mon, 14 Oct 2024 15:16:35 +0100 Subject: [PATCH 72/99] docs: update roadmap (#1279) --- docpages/advanced_reference/roadmap.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docpages/advanced_reference/roadmap.md b/docpages/advanced_reference/roadmap.md index 0914ac759e..0a50a5092a 100644 --- a/docpages/advanced_reference/roadmap.md +++ b/docpages/advanced_reference/roadmap.md @@ -2,6 +2,11 @@ At present our roadmap is: -*Short term (6 months):*: Stabilise coroutine support and release it as stable a feature +## Short term (1 month) +* Implement user apps support -*Long term*: Continue development of the library to implement Discord new features as they add them. Discord does not share their internal roadmap with library developers, so we are informed of these new features shortly before they become public given enough time to implement them. This is our permanent ongoing goal. +## Medium term (6 months) +* Stabilise DAVE E2EE support and release it as stable a feature + +## Long term +* Continue development of the library to implement Discord new features as they add them. Discord does not share their internal roadmap with library developers, so we are informed of these new features shortly before they become public given enough time to implement them. This is our permanent ongoing goal. From fe6f15fb2fbc992fb313a30d0af61f4cb2abf998 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Mon, 14 Oct 2024 16:11:58 +0100 Subject: [PATCH 73/99] fix: DAVE! client join/part re-derive client ratchets and privacy code (#1264) Co-authored-by: Neko Life --- .cspell.json | 3 +- include/dpp/discordvoiceclient.h | 55 ++- src/dpp/dave/decryptor.cpp | 3 +- src/dpp/dave/encryptor.cpp | 12 +- src/dpp/dave/frame_processors.cpp | 22 ++ src/dpp/dave/session.cpp | 4 +- src/dpp/discordvoiceclient.cpp | 17 +- src/dpp/voice/enabled/displayable_code.cpp | 4 + src/dpp/voice/enabled/enabled.h | 51 ++- src/dpp/voice/enabled/handle_frame.cpp | 388 +++++++++++++++------ src/dpp/voice/enabled/opus.cpp | 3 +- 11 files changed, 428 insertions(+), 134 deletions(-) diff --git a/.cspell.json b/.cspell.json index e19a259067..3cfb280732 100644 --- a/.cspell.json +++ b/.cspell.json @@ -147,7 +147,8 @@ "chacha", "nullopt", "chrono", - "ciphersuite" + "ciphersuite", + "rmap" ], "flagWords": [ "hte" diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 69e0abd7f8..6ce21bf309 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -154,7 +154,6 @@ enum voice_websocket_opcode_t : uint8_t { voice_opcode_connection_hello = 8, voice_opcode_connection_resumed = 9, voice_opcode_multiple_clients_connect = 11, - voice_opcode_client_connect = 12, voice_opcode_client_disconnect = 13, voice_opcode_media_sink = 15, voice_client_flags = 18, @@ -167,7 +166,7 @@ enum voice_websocket_opcode_t : uint8_t { voice_client_dave_mls_key_package = 26, voice_client_dave_mls_proposals = 27, voice_client_dave_mls_commit_message = 28, - voice_client_dave_announce_commit_transaction = 29, + voice_client_dave_announce_commit_transition = 29, voice_client_dave_mls_welcome = 30, voice_client_dave_mls_invalid_commit_welcome = 31, }; @@ -207,7 +206,7 @@ struct dave_binary_header_t { [[nodiscard]] std::vector get_data() const; /** - * Get transition ID for process_welcome + * Get transition ID for process_commit and process_welcome * * @return Transition ID */ @@ -216,7 +215,7 @@ struct dave_binary_header_t { private: /** * @brief Transition id, only valid when the opcode is - * welcome state. Use get_transition_id() to obtain value. + * commit and welcome state. Use get_transition_id() to obtain value. */ uint16_t transition_id; }; @@ -478,6 +477,12 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ std::set dave_mls_user_list; + /** + * @brief The list of users that have left the voice channel but + * not yet removed from MLS group. + */ + std::set dave_mls_pending_remove_list; + /** * @brief File descriptor for UDP connection */ @@ -678,6 +683,12 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ size_t encode(uint8_t *input, size_t inDataSize, uint8_t *output, size_t &outDataSize); + /** + * Updates DAVE MLS ratchets for users in the VC + * @param force True to force updating of ratchets regardless of state + */ + void update_ratchets(bool force = false); + public: /** @@ -1184,6 +1195,42 @@ class DPP_EXPORT discord_voice_client : public websocket_client * which internally uses scrypt. */ void get_user_privacy_code(const dpp::snowflake user, privacy_code_callback_t callback) const; + + /** + * @brief Notify gateway ready for a DAVE transition. + * + * Fires Voice Ready event when appropriate. + * + * https://daveprotocol.com/#commit-handling + * + * @param data Websocket frame data + */ + void ready_for_transition(const std::string &data); + + /** + * @brief Reset dave session, send voice_client_dave_mls_invalid_commit_welcome + * payload with current transition Id and our new key package to gateway. + * + * https://daveprotocol.com/#recovery-from-invalid-commit-or-welcome + */ + void recover_from_invalid_commit_welcome(); + + /** + * @brief Execute pending protocol upgrade/downgrade to/from dave. + * @return true if did an upgrade/downgrade + */ + bool execute_pending_upgrade_downgrade(); + + /** + * @brief Reset dave session and prepare initial session group. + */ + void reinit_dave_mls_group(); + + /** + * @brief Process roster map from commit/welcome. + * @param rmap Roster map + */ + void process_mls_group_rosters(const std::map>& rmap); }; } // namespace dpp diff --git a/src/dpp/dave/decryptor.cpp b/src/dpp/dave/decryptor.cpp index e2fa7272be..54bbd721d7 100755 --- a/src/dpp/dave/decryptor.cpp +++ b/src/dpp/dave/decryptor.cpp @@ -36,8 +36,7 @@ namespace dpp::dave { constexpr auto kStatsInterval = 10s; -void decryptor::transition_to_key_ratchet(std::unique_ptr keyRatchet, - duration transitionExpiry) +void decryptor::transition_to_key_ratchet(std::unique_ptr keyRatchet, duration transitionExpiry) { if (keyRatchet) { creator.log(dpp::ll_trace, "Transitioning to new key ratchet, expiry: " + std::to_string(transitionExpiry.count())); diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp index b169662754..879976942f 100755 --- a/src/dpp/dave/encryptor.cpp +++ b/src/dpp/dave/encryptor.cpp @@ -39,8 +39,6 @@ using namespace std::chrono_literals; namespace dpp::dave { -constexpr auto kStatsInterval = 10s; - void encryptor::set_key_ratchet(std::unique_ptr keyRatchet) { std::lock_guard lock(keyGenMutex_); @@ -56,12 +54,7 @@ void encryptor::set_passthrough_mode(bool passthroughMode) update_current_protocol_version(passthroughMode ? 0 : max_protocol_version()); } -encryptor::result_code encryptor::encrypt(media_type mediaType, - uint32_t ssrc, - array_view frame, - array_view encryptedFrame, - size_t* bytesWritten) -{ +encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, array_view frame, array_view encryptedFrame, size_t* bytesWritten) { if (mediaType != media_audio && mediaType != media_video) { creator.log(dpp::ll_warning, "encrypt failed, invalid media type: " + std::to_string(static_cast(mediaType))); return result_code::rc_encryption_failure; @@ -270,8 +263,7 @@ encryptor::cryptor_and_nonce encryptor::get_next_cryptor_and_nonce() return {nullptr, 0}; } - auto generation = compute_wrapped_generation(currentKeyGeneration_, - ++truncatedNonce_ >> RATCHET_GENERATION_SHIFT_BITS); + auto generation = compute_wrapped_generation(currentKeyGeneration_, ++truncatedNonce_ >> RATCHET_GENERATION_SHIFT_BITS); if (generation != currentKeyGeneration_ || !cryptor_) { currentKeyGeneration_ = generation; diff --git a/src/dpp/dave/frame_processors.cpp b/src/dpp/dave/frame_processors.cpp index 9cd8b8c4a6..15177a877e 100755 --- a/src/dpp/dave/frame_processors.cpp +++ b/src/dpp/dave/frame_processors.cpp @@ -39,6 +39,26 @@ namespace dpp::dave { +#if defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) + /** + * @brief ARM does not have a builtin for overflow detecting add + * This implements a non-UB version of that. + * @param carry_in Input carry from previous add + * @param a First operand + * @param b Second operand + * @param result Output result + * @return True if overflow occured, false if it didn't + */ + inline uint8_t addcarry_size_t(size_t carry_in, size_t a, size_t b, size_t* result) { + size_t partial_sum = a + b; + uint8_t carry1 = (partial_sum < a); + size_t final_sum = partial_sum + carry_in; + uint8_t carry2 = (final_sum < partial_sum); + *result = final_sum; + return carry1 || carry2; + } +#endif + std::pair OverflowAdd(size_t a, size_t b) { size_t res; @@ -46,6 +66,8 @@ std::pair OverflowAdd(size_t a, size_t b) bool didOverflow = _addcarry_u64(0, a, b, &res); #elif defined(_MSC_VER) && defined(_M_IX86) bool didOverflow = _addcarry_u32(0, a, b, &res); +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) + bool didOverflow = addcarry_size_t(0, a, b, &res); #else bool didOverflow = __builtin_add_overflow(a, b, &res); #endif diff --git a/src/dpp/dave/session.cpp b/src/dpp/dave/session.cpp index b619a2913a..5aa0859856 100755 --- a/src/dpp/dave/session.cpp +++ b/src/dpp/dave/session.cpp @@ -365,9 +365,7 @@ catch (const std::exception& e) { return failed_t{}; } -std::optional session::process_welcome( - std::vector welcome, - std::set const& recognizedUserIDs) noexcept +std::optional session::process_welcome(std::vector welcome, std::set const& recognizedUserIDs) noexcept try { if (!has_cryptographic_state_for_welcome()) { creator.log(dpp::ll_warning, "Missing local crypto state necessary to process MLS welcome"); diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 64e1598247..1b8fe7b95f 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -83,8 +83,9 @@ bool discord_voice_client::is_playing() { } uint16_t dave_binary_header_t::get_transition_id() const { - if (opcode != voice_client_dave_mls_welcome) { - throw dpp::logic_exception("Can't get transition ID from buffer that is not of type voice_client_dave_mls_welcome(30)"); + bool has_transition_id = opcode == voice_client_dave_mls_welcome || opcode == voice_client_dave_announce_commit_transition; + if (!has_transition_id) { + throw dpp::logic_exception("Can't get transition ID from buffer that is not of type voice_client_dave_announce_commit_transition(29) or voice_client_dave_mls_welcome(30)"); } return transition_id; } @@ -96,7 +97,9 @@ dave_binary_header_t::dave_binary_header_t(const std::string& buffer) { seq = (buffer[0] << 8) | buffer[1]; opcode = buffer[2]; transition_id = (buffer[3] << 8) | buffer[4]; - package.assign(buffer.begin() + (opcode == voice_client_dave_mls_welcome ? 5 : 3), buffer.end()); + + bool has_transition_id = opcode == voice_client_dave_mls_welcome || opcode == voice_client_dave_announce_commit_transition; + package.assign(buffer.begin() + (has_transition_id ? 5 : 3), buffer.end()); } std::vector dave_binary_header_t::get_data() const { @@ -127,13 +130,17 @@ void discord_voice_client::get_user_privacy_code(const dpp::snowflake user, priv bool discord_voice_client::is_end_to_end_encrypted() const { #ifdef HAVE_VOICE - if (mls_state == nullptr) { + if (mls_state == nullptr || mls_state->encryptor == nullptr) { return false; } bool has_pending_downgrade = mls_state->pending_transition.is_pending && mls_state->pending_transition.protocol_version != dave_version_1; - return !has_pending_downgrade && !mls_state->privacy_code.empty(); + /* + * A dave_version 0 should be enough to know we're in non-e2ee session, we should also check for pending downgrade and + * whether session encryptor actually has key rachet set to encrypt opus packets. + */ + return !has_pending_downgrade && dave_version != dave_version_none && mls_state->encryptor->has_key_ratchet(); #else return false; #endif diff --git a/src/dpp/voice/enabled/displayable_code.cpp b/src/dpp/voice/enabled/displayable_code.cpp index 364ace13d4..685ff5d204 100644 --- a/src/dpp/voice/enabled/displayable_code.cpp +++ b/src/dpp/voice/enabled/displayable_code.cpp @@ -31,6 +31,10 @@ namespace dpp { std::string generate_displayable_code(const std::vector &data, size_t desired_length = 30, size_t group_size = 5) { + if (data.empty()) { + return ""; + } + const size_t group_modulus = std::pow(10, group_size); std::stringstream result; diff --git a/src/dpp/voice/enabled/enabled.h b/src/dpp/voice/enabled/enabled.h index ef821f8d66..10df19081c 100644 --- a/src/dpp/voice/enabled/enabled.h +++ b/src/dpp/voice/enabled/enabled.h @@ -69,19 +69,66 @@ namespace dpp { +/** + * @brief A list of MLS decryptors for decrypting inbound audio from users by snowflake id + */ +using decryptor_list = std::map>; + +/** + * @brief Holds all internal DAVE E2EE encryption state + */ struct dave_state { + /** + * @brief libdave session + */ std::unique_ptr dave_session{}; + /** + * @brief Our key package + */ std::shared_ptr<::mlspp::SignaturePrivateKey> mls_key; - std::vector cached_commit; + /** + * @brief Current transition ID + */ uint64_t transition_id{0}; + /** + * @brief Have sent ready event to listeners + */ + bool done_ready{false}; + /** + * @brief Details of upcoming transition + */ struct { + /** + * @brief pending next transition ID + */ uint64_t id{0}; + /** + * @brief New upcoming protocol version + */ uint64_t protocol_version{0}; + /** + * @brief True if transition is pending + */ bool is_pending{false}; } pending_transition; - std::map> decryptors; + /** + * @brief Decryptors for inbound audio streams + */ + decryptor_list decryptors; + /** + * @brief Encryptor for outbound audio stream + */ std::unique_ptr encryptor; + /** + * @brief Current privacy code, or empty string if + * MLS group is not established. + */ std::string privacy_code; + + /** + * @brief Cached roster map to track rosters changes. + */ + dave::roster_map cached_roster_map; }; /** diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp index 060fb9692f..7b85cb7820 100644 --- a/src/dpp/voice/enabled/handle_frame.cpp +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -31,6 +31,64 @@ namespace dpp { +using namespace std::chrono_literals; + +/** + * @brief How long to wait after deriving new key ratchets to expire the old ones + */ +constexpr dave::decryptor::duration RATCHET_EXPIRY = 10s; + +void discord_voice_client::update_ratchets(bool force) { + + if (!mls_state || !mls_state->dave_session) { + return; + } + + /** + * Update everyone's ratchets including the bot. Whenever a new user joins or a user leaves, this invalidates + * all the old ratchets and they are replaced with new ones and the old ones are invalidated after RATCHET_EXPIRY seconds. + */ + log(ll_debug, "Updating MLS ratchets for " + std::to_string(dave_mls_user_list.size() + 1) + " user(s)"); + for (const auto& user : dave_mls_user_list) { + dpp::snowflake u{user}; + if (u == creator->me.id) { + continue; + } + decryptor_list::iterator decryptor; + /* New user join/old user leave - insert new ratchets if they don't exist */ + decryptor = mls_state->decryptors.find(u); + if (decryptor == mls_state->decryptors.end()) { + log(ll_debug, "Inserting decryptor key ratchet for NEW user: " + user + ", protocol version: " + std::to_string(mls_state->dave_session->get_protocol_version())); + auto [iter, inserted] = mls_state->decryptors.emplace(u, std::make_unique(*creator)); + decryptor = iter; + } + decryptor->second->transition_to_key_ratchet(mls_state->dave_session->get_key_ratchet(user), RATCHET_EXPIRY); + } + + /* + * Encryptor should always be present on execute transition. + * Should we throw error if it's missing here? + */ + if (mls_state->encryptor) { + /* Updating key rachet should always be done on execute transition. Generally after group member add/remove. */ + log(ll_debug, "Setting key ratchet for sending audio..."); + mls_state->encryptor->set_key_ratchet(mls_state->dave_session->get_key_ratchet(creator->me.id.str())); + } + + /** + * https://www.ietf.org/archive/id/draft-ietf-mls-protocol-14.html#name-epoch-authenticators + * 9.7. Epoch Authenticators + * The main MLS key schedule provides a per-epoch epoch_authenticator. If one member of the group is being impersonated by an active attacker, + * the epoch_authenticator computed by their client will differ from those computed by the other group members. + */ + std::string old_code = mls_state->privacy_code; + mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->get_last_epoch_authenticator()); + if (!mls_state->privacy_code.empty() && mls_state->privacy_code != old_code) { + log(ll_info, "New E2EE Privacy Code: " + mls_state->privacy_code); + } + +} + bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcode) { json j; @@ -41,14 +99,14 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod dave_binary_header_t dave_header(data); + /* These binaries also contains sequence number we need to save */ + receive_sequence = dave_header.seq; + switch (dave_header.opcode) { case voice_client_dave_mls_external_sender: { log(ll_debug, "voice_client_dave_mls_external_sender"); mls_state->dave_session->set_external_sender(dave_header.get_data()); - - mls_state->encryptor = std::make_unique(*creator); - mls_state->decryptors.clear(); } break; case voice_client_dave_mls_proposals: { @@ -57,66 +115,53 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod std::optional> response = mls_state->dave_session->process_proposals(dave_header.get_data(), dave_mls_user_list); if (response.has_value()) { auto r = response.value(); - mls_state->cached_commit = r; r.insert(r.begin(), voice_client_dave_mls_commit_message); this->write(std::string_view(reinterpret_cast(r.data()), r.size()), OP_BINARY); } } break; - case voice_client_dave_announce_commit_transaction: { - log(ll_debug, "voice_client_dave_announce_commit_transaction"); - auto r = mls_state->dave_session->process_commit(mls_state->cached_commit); - for (const auto& user : dave_mls_user_list) { - log(ll_debug, "Setting decryptor key ratchet for user: " + user + ", protocol version: " + std::to_string(mls_state->dave_session->get_protocol_version())); - dpp::snowflake u{user}; - mls_state->decryptors.emplace(u, std::make_unique(*creator)); - mls_state->decryptors.find(u)->second->transition_to_key_ratchet(mls_state->dave_session->get_key_ratchet(user)); - } - mls_state->encryptor->set_key_ratchet(mls_state->dave_session->get_key_ratchet(creator->me.id.str())); + case voice_client_dave_announce_commit_transition: { + this->mls_state->transition_id = dave_header.get_transition_id(); + log(ll_debug, "voice_client_dave_announce_commit_transition"); + auto r = mls_state->dave_session->process_commit(dave_header.get_data()); - /** - * https://www.ietf.org/archive/id/draft-ietf-mls-protocol-14.html#name-epoch-authenticators - * 9.7. Epoch Authenticators - * The main MLS key schedule provides a per-epoch epoch_authenticator. If one member of the group is being impersonated by an active attacker, - * the epoch_authenticator computed by their client will differ from those computed by the other group members. + /* + * We need to do recovery here when we failed processing the message */ - mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->get_last_epoch_authenticator()); - log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); - - if (!creator->on_voice_ready.empty()) { - voice_ready_t rdy(nullptr, data); - rdy.voice_client = this; - rdy.voice_channel_id = this->channel_id; - creator->on_voice_ready.call(rdy); + if (!std::holds_alternative(r)) { + log(ll_debug, "Unable to process commit in transition " + std::to_string(this->mls_state->transition_id)); + + this->recover_from_invalid_commit_welcome(); + break; } + + auto rmap = std::get(r); + this->process_mls_group_rosters(rmap); + + this->ready_for_transition(data); } break; case voice_client_dave_mls_welcome: { this->mls_state->transition_id = dave_header.get_transition_id(); log(ll_debug, "voice_client_dave_mls_welcome with transition id " + std::to_string(this->mls_state->transition_id)); + + /* We should always recognize our own selves, but do we? */ + dave_mls_user_list.insert(this->creator->me.id.str()); + auto r = mls_state->dave_session->process_welcome(dave_header.get_data(), dave_mls_user_list); - if (r.has_value()) { - for (const auto& user : dave_mls_user_list) { - log(ll_debug, "Setting decryptor key ratchet for user: " + user + ", protocol version: " + std::to_string(mls_state->dave_session->get_protocol_version())); - dpp::snowflake u{user}; - mls_state->decryptors.emplace(u, std::make_unique(*creator)); - mls_state->decryptors.find(u)->second->transition_to_key_ratchet(mls_state->dave_session->get_key_ratchet(user)); - } - mls_state->encryptor->set_key_ratchet(mls_state->dave_session->get_key_ratchet(creator->me.id.str())); + + /* + * We need to do recovery here when we failed processing the message + */ + if (!r.has_value()) { + log(ll_debug, "Unable to process welcome in transition " + std::to_string(this->mls_state->transition_id)); + + this->recover_from_invalid_commit_welcome(); + break; } - mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->get_last_epoch_authenticator()); - log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); - json obj = { - { "op", voice_client_dave_transition_ready }, - { - "d", - { - { "transition_id", this->mls_state->transition_id }, - } - } - }; - this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + this->process_mls_group_rosters(r.value()); + this->ready_for_transition(data); } break; default: @@ -168,8 +213,19 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } break; case voice_opcode_multiple_clients_connect: { - dave_mls_user_list = j["d"]["user_ids"]; - log(ll_debug, "Number of clients in voice channel: " + std::to_string(dave_mls_user_list.size())); + /** + * @brief The list of users that just joined for DAVE + */ + std::set joining_dave_users = j["d"]["user_ids"]; + + dave_mls_user_list.insert(joining_dave_users.begin(), joining_dave_users.end()); + + /* Remove this user from pending remove list if exist */ + for (const auto &user : joining_dave_users) { + dave_mls_pending_remove_list.erase(user); + } + + log(ll_debug, "New of clients in voice channel: " + std::to_string(joining_dave_users.size()) + " total is " + std::to_string(dave_mls_user_list.size())); } break; case voice_client_dave_mls_invalid_commit_welcome: { @@ -181,53 +237,50 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod log(ll_debug, "voice_client_dave_execute_transition"); this->mls_state->transition_id = j["d"]["transition_id"]; - if (this->mls_state->pending_transition.is_pending) { - if (this->mls_state->transition_id != this->mls_state->pending_transition.id) { - log(ll_debug, "voice_client_dave_execute_transition unexpected transition_id, we never received voice_client_dave_prepare_transition event with this id: " + std::to_string(this->mls_state->pending_transition.id)); - } else { - dave_version = this->mls_state->pending_transition.protocol_version == 1 ? dave_version_1 : dave_version_none; - - if (this->mls_state->pending_transition.protocol_version != 0 && dave_version == dave_version_none) { - log(ll_debug, "voice_client_dave_execute_transition unexpected protocol version: " + std::to_string(this->mls_state->pending_transition.protocol_version)+ " in transition " + std::to_string(this->mls_state->pending_transition.id)); - } - - this->mls_state->privacy_code.clear(); - this->dave_mls_user_list.clear(); - - this->mls_state->pending_transition.is_pending = false; - } + if (this->mls_state->pending_transition.is_pending && this->execute_pending_upgrade_downgrade()) { + break; } + + /* + * Execute transition from a commit/welcome message. + */ + update_ratchets(); } break; /* "The protocol only uses this opcode to indicate when a downgrade to protocol version 0 is upcoming." */ case voice_client_dave_prepare_transition: { - uint64_t transition_id = j["d"]["transition_id"]; + this->mls_state->transition_id = j["d"]["transition_id"]; uint64_t protocol_version = j["d"]["protocol_version"]; - this->mls_state->pending_transition = {transition_id, protocol_version, true}; - log(ll_debug, "voice_client_dave_prepare_transition version=" + std::to_string(protocol_version) + " for transition " + std::to_string(transition_id)); - json obj = { - { "op", voice_client_dave_transition_ready }, - { - "d", + this->mls_state->pending_transition = {this->mls_state->transition_id, protocol_version, true}; + + log(ll_debug, "voice_client_dave_prepare_transition version=" + std::to_string(protocol_version) + " for transition " + std::to_string(this->mls_state->transition_id)); + + if (this->mls_state->transition_id == 0) { + this->execute_pending_upgrade_downgrade(); + } else { + json obj = { + { "op", voice_client_dave_transition_ready }, { - { "transition_id", this->mls_state->transition_id }, + "d", + { + { "transition_id", this->mls_state->transition_id }, + } } - } - }; - this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + } } break; case voice_client_dave_prepare_epoch: { uint64_t protocol_version = j["d"]["protocol_version"]; - uint64_t epoch = j["d"]["epoch"]; + uint32_t epoch = j["d"]["epoch"]; log(ll_debug, "voice_client_dave_prepare_epoch version=" + std::to_string(protocol_version) + " for epoch " + std::to_string(epoch)); if (epoch == 1) { - mls_state->dave_session->reset(); - mls_state->dave_session->init(dave::max_protocol_version(), channel_id, creator->me.id.str(), mls_state->mls_key); - auto key_response = mls_state->dave_session->get_marshalled_key_package(); - key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); - this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); + /* An epoch 1 is the start of new dave session, update dave_version */ + dave_version = protocol_version == 1 ? dave_version_1 : dave_version_none; + + this->reinit_dave_mls_group(); } } break; @@ -235,17 +288,17 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod case voice_opcode_client_disconnect: { if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null()) { snowflake u_id = snowflake_not_null(&j["d"], "user_id"); - auto it = std::find_if(ssrc_map.begin(), ssrc_map.end(), - [&u_id](const auto & p) { return p.second == u_id; }); + + log(ll_debug, "User left voice channel: " + u_id.str()); + + auto it = std::find_if(ssrc_map.begin(), ssrc_map.end(), [&u_id](const auto & p) { return p.second == u_id; }); if (it != ssrc_map.end()) { ssrc_map.erase(it); } - auto it_dave = dave_mls_user_list.find(j["d"]["user_id"]); - if (it_dave != dave_mls_user_list.end()) { - dave_mls_user_list.erase(it_dave); - } + /* Mark this user for remove on immediate upgrade */ + dave_mls_pending_remove_list.insert(u_id.str()); if (!creator->on_voice_client_disconnect.empty()) { voice_client_disconnect_t vcd(nullptr, data); @@ -257,9 +310,7 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } break; /* Speaking */ - case voice_opcode_client_speaking: - /* Client Connect (doesn't seem to work) */ - case voice_opcode_client_connect: { + case voice_opcode_client_speaking: { if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null() && j["d"].find("ssrc") != j["d"].end() && !j["d"]["ssrc"].is_null() && j["d"]["ssrc"].is_number_integer()) { @@ -343,27 +394,26 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod bool ready_now = false; if (dave_version != dave_version_none) { + /* DAVE ready later */ if (j["d"]["dave_protocol_version"] != static_cast(dave_version)) { log(ll_error, "We requested DAVE E2EE but didn't receive it from the server, downgrading..."); dave_version = dave_version_none; ready_now = true; + } else { + if (mls_state == nullptr) { + mls_state = std::make_unique(); + } + if (mls_state->dave_session == nullptr) { + mls_state->dave_session = std::make_unique( + *creator, + nullptr, "", [this](std::string const &s1, std::string const &s2) { + log(ll_debug, "DAVE: " + s1 + ", " + s2); + }); + } + this->reinit_dave_mls_group(); } - - if (mls_state == nullptr) { - mls_state = std::make_unique(); - } - if (mls_state->dave_session == nullptr) { - mls_state->dave_session = std::make_unique( - *creator, - nullptr, "", [this](std::string const& s1, std::string const& s2) { - log(ll_debug, "Dave session constructor callback: " + s1 + ", " + s2); - }); - mls_state->dave_session->init(dave::max_protocol_version(), channel_id, creator->me.id.str(), mls_state->mls_key); - } - auto key_response = mls_state->dave_session->get_marshalled_key_package(); - key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); - this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); } else { + /* Non-DAVE ready immediately */ ready_now = true; } @@ -450,4 +500,132 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } +/* + * Handle DAVE frame utilities. + */ + +void discord_voice_client::ready_for_transition(const std::string &data) { + log(ll_debug, "Ready to execute transition " + std::to_string(this->mls_state->transition_id)); + json obj = { + { "op", voice_client_dave_transition_ready }, + { + "d", + { + { "transition_id", this->mls_state->transition_id }, + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + this->mls_state->pending_transition.id = this->mls_state->transition_id; + + /* When the included transition ID is 0, the transition is for (re)initialization, and it can be executed immediately. */ + if (this->mls_state->transition_id == 0) { + /* Mark state ready and update ratchets the first time */ + update_ratchets(); + } + + if (!this->mls_state->done_ready) { + this->mls_state->done_ready = true; + + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } + } } + +void discord_voice_client::recover_from_invalid_commit_welcome() { + json obj = { + {"op", voice_client_dave_mls_invalid_commit_welcome}, + { + "d", { + "transition_id", this->mls_state->transition_id + } + } + }; + this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + this->reinit_dave_mls_group(); +} + +bool discord_voice_client::execute_pending_upgrade_downgrade() { + bool did_upgrade_downgrade = false; + + if (this->mls_state->transition_id != this->mls_state->pending_transition.id) { + log(ll_debug, "execute_pending_upgrade_downgrade unexpected transition_id, we never received voice_client_dave_prepare_transition event with this id: " + std::to_string(this->mls_state->transition_id)); + } else if (dave_version != this->mls_state->pending_transition.protocol_version) { + dave_version = this->mls_state->pending_transition.protocol_version == 1 ? dave_version_1 : dave_version_none; + + if (this->mls_state->pending_transition.protocol_version != 0 && dave_version == dave_version_none) { + log(ll_debug, "execute_pending_upgrade_downgrade unexpected protocol version: " + std::to_string(this->mls_state->pending_transition.protocol_version)+ " in transition " + std::to_string(this->mls_state->transition_id)); + } else { + log(ll_debug, "execute_pending_upgrade_downgrade upgrade/downgrade successful"); + did_upgrade_downgrade = true; + } + } + + this->mls_state->pending_transition.is_pending = false; + return did_upgrade_downgrade; +} + +void discord_voice_client::reinit_dave_mls_group() { + mls_state->dave_session->init(dave::max_protocol_version(), channel_id, creator->me.id.str(), mls_state->mls_key); + + auto key_response = mls_state->dave_session->get_marshalled_key_package(); + key_response.insert(key_response.begin(), voice_client_dave_mls_key_package); + this->write(std::string_view(reinterpret_cast(key_response.data()), key_response.size()), OP_BINARY); + + mls_state->encryptor = std::make_unique(*creator); + mls_state->decryptors.clear(); + + mls_state->cached_roster_map.clear(); + + mls_state->privacy_code.clear(); + + /* Remove any user in pending remove from MLS member list */ + for (const auto &user : dave_mls_pending_remove_list) { + dave_mls_user_list.erase(user); + } + dave_mls_pending_remove_list.clear(); +} + +void discord_voice_client::process_mls_group_rosters(const dave::roster_map &rmap) { + log(ll_debug, "process_mls_group_rosters of size: " + std::to_string(rmap.size())); + + for (const auto &[k, v] : rmap) { + bool user_has_key = !v.empty(); + + /* Debug log for changed and added keys */ + auto cached_user = mls_state->cached_roster_map.find(k); + if (cached_user == mls_state->cached_roster_map.end()) { + log(ll_debug, "Added user to MLS Group: " + std::to_string(k)); + } else if (user_has_key && cached_user->second != v) { + log(ll_debug, "Changed user key in MLS Group: " + std::to_string(k)); + } + + /* + * Remove user from recognized list. + * Do not remove user with non-empty key. + */ + if (user_has_key) { + continue; + } + + dpp::snowflake u_id(k); + auto u_id_str = u_id.str(); + + log(ll_debug, "Removed user from MLS Group: " + u_id_str); + + dave_mls_user_list.erase(u_id_str); + dave_mls_pending_remove_list.erase(u_id_str); + + /* Remove this user's key ratchet */ + mls_state->decryptors.erase(u_id); + } + + mls_state->cached_roster_map = rmap; +} + +} + diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp index 5eb7a77cc4..d99a3776d0 100644 --- a/src/dpp/voice/enabled/opus.cpp +++ b/src/dpp/voice/enabled/opus.cpp @@ -105,9 +105,8 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet log(ll_warning, "DAVE Encryption failure: " + std::to_string(result)); } else { encoded_audio = encrypted_buffer; - encoded_audio_length = encoded_audio.size(); + encoded_audio_length = encrypted_buffer.size(); } - } ++sequence; From b720cc6693a66dd9321bba29af8a53222ed0c89c Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Mon, 14 Oct 2024 17:36:26 +0100 Subject: [PATCH 74/99] refactor(breaking): Deprecate sync calls (#1280) --- .../classes/Generator/SyncGenerator.php | 3 +- include/dpp/cluster_sync_calls.h | 618 ++++++++++++------ src/unittest/test.cpp | 18 +- 3 files changed, 422 insertions(+), 217 deletions(-) diff --git a/buildtools/classes/Generator/SyncGenerator.php b/buildtools/classes/Generator/SyncGenerator.php index e666feffdd..a5c40319a9 100644 --- a/buildtools/classes/Generator/SyncGenerator.php +++ b/buildtools/classes/Generator/SyncGenerator.php @@ -88,7 +88,7 @@ public function checkForChanges(): bool */ public function generateHeaderDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string { - return "$returnType {$currentFunction}_sync($parameters);\n\n"; + return "DPP_DEPRECATED(\"Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html\") $returnType {$currentFunction}_sync($parameters);\n\n"; } /** @@ -107,6 +107,7 @@ public function getCommentArray(): array return [ " * \memberof dpp::cluster", " * @throw dpp::rest_exception upon failure to execute REST function", + " * @deprecated This function is deprecated, please use coroutines instead.", " * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread.", " * Avoid direct use of this function inside an event handler.", ]; diff --git a/include/dpp/cluster_sync_calls.h b/include/dpp/cluster_sync_calls.h index 302e57111a..74db0bff7c 100644 --- a/include/dpp/cluster_sync_calls.h +++ b/include/dpp/cluster_sync_calls.h @@ -38,10 +38,11 @@ * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map global_bulk_command_create_sync(const std::vector &commands); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map global_bulk_command_create_sync(const std::vector &commands); /** * @brief Delete all existing global slash commands. @@ -51,10 +52,11 @@ slashcommand_map global_bulk_command_create_sync(const std::vector * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map global_bulk_command_delete_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map global_bulk_command_delete_sync(); /** * @brief Create a global slash command (a bot can have a maximum of 100 of these). @@ -65,10 +67,11 @@ slashcommand_map global_bulk_command_delete_sync(); * @return slashcommand returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand global_command_create_sync(const slashcommand &s); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand global_command_create_sync(const slashcommand &s); /** * @brief Get a global slash command @@ -79,10 +82,11 @@ slashcommand global_command_create_sync(const slashcommand &s); * @return slashcommand returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand global_command_get_sync(snowflake id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand global_command_get_sync(snowflake id); /** * @brief Delete a global slash command (a bot can have a maximum of 100 of these) @@ -93,10 +97,11 @@ slashcommand global_command_get_sync(snowflake id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation global_command_delete_sync(snowflake id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation global_command_delete_sync(snowflake id); /** * @brief Edit a global slash command (a bot can have a maximum of 100 of these) @@ -107,10 +112,11 @@ confirmation global_command_delete_sync(snowflake id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation global_command_edit_sync(const slashcommand &s); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation global_command_edit_sync(const slashcommand &s); /** * @brief Get the application's global slash commands @@ -120,10 +126,11 @@ confirmation global_command_edit_sync(const slashcommand &s); * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map global_commands_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map global_commands_get_sync(); /** * @brief Create/overwrite guild slash commands. @@ -137,10 +144,11 @@ slashcommand_map global_commands_get_sync(); * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map guild_bulk_command_create_sync(const std::vector &commands, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map guild_bulk_command_create_sync(const std::vector &commands, snowflake guild_id); /** * @brief Delete all existing guild slash commands. @@ -151,10 +159,11 @@ slashcommand_map guild_bulk_command_create_sync(const std::vector * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map guild_bulk_command_delete_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map guild_bulk_command_delete_sync(snowflake guild_id); /** * @brief Get all slash command permissions of a guild @@ -165,10 +174,11 @@ slashcommand_map guild_bulk_command_delete_sync(snowflake guild_id); * @return guild_command_permissions_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -guild_command_permissions_map guild_commands_get_permissions_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") guild_command_permissions_map guild_commands_get_permissions_sync(snowflake guild_id); /** * @brief Edit/Overwrite the permissions of all existing slash commands in a guild @@ -184,10 +194,11 @@ guild_command_permissions_map guild_commands_get_permissions_sync(snowflake guil * @deprecated This has been disabled with updates to Permissions v2. You can use guild_command_edit_permissions instead * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -guild_command_permissions_map guild_bulk_command_edit_permissions_sync(const std::vector &commands, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") guild_command_permissions_map guild_bulk_command_edit_permissions_sync(const std::vector &commands, snowflake guild_id); /** * @brief Create a slash command local to a guild @@ -200,10 +211,11 @@ guild_command_permissions_map guild_bulk_command_edit_permissions_sync(const std * @return slashcommand returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand guild_command_create_sync(const slashcommand &s, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand guild_command_create_sync(const slashcommand &s, snowflake guild_id); /** * @brief Delete a slash command local to a guild @@ -215,10 +227,11 @@ slashcommand guild_command_create_sync(const slashcommand &s, snowflake guild_id * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_command_delete_sync(snowflake id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_command_delete_sync(snowflake id, snowflake guild_id); /** * @brief Edit slash command permissions of a guild @@ -231,10 +244,11 @@ confirmation guild_command_delete_sync(snowflake id, snowflake guild_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_command_edit_permissions_sync(const slashcommand &s, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_command_edit_permissions_sync(const slashcommand &s, snowflake guild_id); /** * @brief Get a slash command of a guild @@ -247,10 +261,11 @@ confirmation guild_command_edit_permissions_sync(const slashcommand &s, snowflak * @return slashcommand returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand guild_command_get_sync(snowflake id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand guild_command_get_sync(snowflake id, snowflake guild_id); /** * @brief Get the permissions for a slash command of a guild @@ -262,10 +277,11 @@ slashcommand guild_command_get_sync(snowflake id, snowflake guild_id); * @return guild_command_permissions returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -guild_command_permissions guild_command_get_permissions_sync(snowflake id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") guild_command_permissions guild_command_get_permissions_sync(snowflake id, snowflake guild_id); /** * @brief Edit a slash command local to a guild @@ -277,10 +293,11 @@ guild_command_permissions guild_command_get_permissions_sync(snowflake id, snowf * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_command_edit_sync(const slashcommand &s, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_command_edit_sync(const slashcommand &s, snowflake guild_id); /** * @brief Get the application's slash commands for a guild @@ -292,10 +309,11 @@ confirmation guild_command_edit_sync(const slashcommand &s, snowflake guild_id); * @return slashcommand_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -slashcommand_map guild_commands_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") slashcommand_map guild_commands_get_sync(snowflake guild_id); /** * @brief Respond to a slash command @@ -308,10 +326,11 @@ slashcommand_map guild_commands_get_sync(snowflake guild_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_response_create_sync(snowflake interaction_id, const std::string &token, const interaction_response &r); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_response_create_sync(snowflake interaction_id, const std::string &token, const interaction_response &r); /** * @brief Edit response to a slash command @@ -323,10 +342,11 @@ confirmation interaction_response_create_sync(snowflake interaction_id, const st * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_response_edit_sync(const std::string &token, const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_response_edit_sync(const std::string &token, const message &m); /** * @brief Get the original response to a slash command @@ -337,10 +357,11 @@ confirmation interaction_response_edit_sync(const std::string &token, const mess * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message interaction_response_get_original_sync(const std::string &token); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message interaction_response_get_original_sync(const std::string &token); /** * @brief Create a followup message to a slash command @@ -352,10 +373,11 @@ message interaction_response_get_original_sync(const std::string &token); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_followup_create_sync(const std::string &token, const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_followup_create_sync(const std::string &token, const message &m); /** * @brief Edit original followup message to a slash command @@ -368,10 +390,11 @@ confirmation interaction_followup_create_sync(const std::string &token, const me * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_followup_edit_original_sync(const std::string &token, const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_followup_edit_original_sync(const std::string &token, const message &m); /** * @brief Delete the initial interaction response @@ -382,10 +405,11 @@ confirmation interaction_followup_edit_original_sync(const std::string &token, c * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_followup_delete_sync(const std::string &token); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_followup_delete_sync(const std::string &token); /** * @brief Edit followup message to a slash command @@ -398,10 +422,11 @@ confirmation interaction_followup_delete_sync(const std::string &token); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation interaction_followup_edit_sync(const std::string &token, const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation interaction_followup_edit_sync(const std::string &token, const message &m); /** * @brief Get the followup message to a slash command @@ -413,10 +438,11 @@ confirmation interaction_followup_edit_sync(const std::string &token, const mess * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message interaction_followup_get_sync(const std::string &token, snowflake message_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message interaction_followup_get_sync(const std::string &token, snowflake message_id); /** * @brief Get the original followup message to a slash command @@ -428,10 +454,11 @@ message interaction_followup_get_sync(const std::string &token, snowflake messag * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message interaction_followup_get_original_sync(const std::string &token); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message interaction_followup_get_original_sync(const std::string &token); /** * @brief Get all auto moderation rules for a guild @@ -440,10 +467,11 @@ message interaction_followup_get_original_sync(const std::string &token); * @return automod_rule_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -automod_rule_map automod_rules_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") automod_rule_map automod_rules_get_sync(snowflake guild_id); /** * @brief Get a single auto moderation rule @@ -453,10 +481,11 @@ automod_rule_map automod_rules_get_sync(snowflake guild_id); * @return automod_rule returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -automod_rule automod_rule_get_sync(snowflake guild_id, snowflake rule_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") automod_rule automod_rule_get_sync(snowflake guild_id, snowflake rule_id); /** * @brief Create an auto moderation rule @@ -466,10 +495,11 @@ automod_rule automod_rule_get_sync(snowflake guild_id, snowflake rule_id); * @return automod_rule returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -automod_rule automod_rule_create_sync(snowflake guild_id, const automod_rule& r); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") automod_rule automod_rule_create_sync(snowflake guild_id, const automod_rule& r); /** * @brief Edit an auto moderation rule @@ -479,10 +509,11 @@ automod_rule automod_rule_create_sync(snowflake guild_id, const automod_rule& r) * @return automod_rule returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -automod_rule automod_rule_edit_sync(snowflake guild_id, const automod_rule& r); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") automod_rule automod_rule_edit_sync(snowflake guild_id, const automod_rule& r); /** * @brief Delete an auto moderation rule @@ -492,10 +523,11 @@ automod_rule automod_rule_edit_sync(snowflake guild_id, const automod_rule& r); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation automod_rule_delete_sync(snowflake guild_id, snowflake rule_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation automod_rule_delete_sync(snowflake guild_id, snowflake rule_id); /** * @brief Create a channel @@ -513,10 +545,11 @@ confirmation automod_rule_delete_sync(snowflake guild_id, snowflake rule_id); * @return channel returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel channel_create_sync(const class channel &c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel channel_create_sync(const class channel &c); /** * @brief Remove a permission from a channel @@ -528,10 +561,11 @@ channel channel_create_sync(const class channel &c); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_delete_permission_sync(const class channel &c, snowflake overwrite_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_delete_permission_sync(const class channel &c, snowflake overwrite_id); /** * @brief Delete a channel @@ -542,10 +576,11 @@ confirmation channel_delete_permission_sync(const class channel &c, snowflake ov * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_delete_sync(snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_delete_sync(snowflake channel_id); /** * @brief Edit a channel's permissions @@ -561,10 +596,11 @@ confirmation channel_delete_sync(snowflake channel_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_edit_permissions_sync(const class channel &c, const snowflake overwrite_id, const uint64_t allow, const uint64_t deny, const bool member); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_edit_permissions_sync(const class channel &c, const snowflake overwrite_id, const uint64_t allow, const uint64_t deny, const bool member); /** * @brief Edit a channel's permissions @@ -580,10 +616,11 @@ confirmation channel_edit_permissions_sync(const class channel &c, const snowfla * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_edit_permissions_sync(const snowflake channel_id, const snowflake overwrite_id, const uint64_t allow, const uint64_t deny, const bool member); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_edit_permissions_sync(const snowflake channel_id, const snowflake overwrite_id, const uint64_t allow, const uint64_t deny, const bool member); /** * @brief Edit multiple channels positions @@ -598,10 +635,11 @@ confirmation channel_edit_permissions_sync(const snowflake channel_id, const sno * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_edit_positions_sync(const std::vector &c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_edit_positions_sync(const std::vector &c); /** * @brief Edit a channel @@ -612,10 +650,11 @@ confirmation channel_edit_positions_sync(const std::vector &c); * @return channel returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel channel_edit_sync(const class channel &c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel channel_edit_sync(const class channel &c); /** * @brief Follow an announcement (news) channel @@ -626,10 +665,11 @@ channel channel_edit_sync(const class channel &c); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_follow_news_sync(const class channel &c, snowflake target_channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_follow_news_sync(const class channel &c, snowflake target_channel_id); /** * @brief Get a channel @@ -640,10 +680,11 @@ confirmation channel_follow_news_sync(const class channel &c, snowflake target_c * @return channel returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel channel_get_sync(snowflake c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel channel_get_sync(snowflake c); /** * @brief Create invite for a channel @@ -655,10 +696,11 @@ channel channel_get_sync(snowflake c); * @return invite returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -invite channel_invite_create_sync(const class channel &c, const class invite &i); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") invite channel_invite_create_sync(const class channel &c, const class invite &i); /** * @brief Get invites for a channel @@ -669,10 +711,11 @@ invite channel_invite_create_sync(const class channel &c, const class invite &i) * @return invite_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -invite_map channel_invites_get_sync(const class channel &c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") invite_map channel_invites_get_sync(const class channel &c); /** * @brief Trigger channel typing indicator @@ -682,10 +725,11 @@ invite_map channel_invites_get_sync(const class channel &c); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_typing_sync(const class channel &c); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_typing_sync(const class channel &c); /** * @brief Trigger channel typing indicator @@ -695,10 +739,11 @@ confirmation channel_typing_sync(const class channel &c); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_typing_sync(snowflake cid); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_typing_sync(snowflake cid); /** * @brief Get all channels for a guild @@ -709,10 +754,11 @@ confirmation channel_typing_sync(snowflake cid); * @return channel_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel_map channels_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel_map channels_get_sync(snowflake guild_id); /** * @brief Set the status of a voice channel. @@ -724,10 +770,11 @@ channel_map channels_get_sync(snowflake guild_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation channel_set_voice_status_sync(snowflake channel_id, const std::string& status); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation channel_set_voice_status_sync(snowflake channel_id, const std::string& status); /** * @brief Create a dm channel @@ -737,10 +784,11 @@ confirmation channel_set_voice_status_sync(snowflake channel_id, const std::stri * @return channel returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel create_dm_channel_sync(snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel create_dm_channel_sync(snowflake user_id); /** * @brief Get current user DM channels @@ -748,10 +796,11 @@ channel create_dm_channel_sync(snowflake user_id); * @return channel_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -channel_map current_user_get_dms_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") channel_map current_user_get_dms_sync(); /** * @brief Create a direct message, also create the channel for the direct message if needed @@ -765,10 +814,11 @@ channel_map current_user_get_dms_sync(); * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message direct_message_create_sync(snowflake user_id, const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message direct_message_create_sync(snowflake user_id, const message &m); /** * @brief Adds a recipient to a Group DM using their access token @@ -781,10 +831,11 @@ message direct_message_create_sync(snowflake user_id, const message &m); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation gdm_add_sync(snowflake channel_id, snowflake user_id, const std::string &access_token, const std::string &nick); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation gdm_add_sync(snowflake channel_id, snowflake user_id, const std::string &access_token, const std::string &nick); /** * @brief Removes a recipient from a Group DM @@ -795,10 +846,11 @@ confirmation gdm_add_sync(snowflake channel_id, snowflake user_id, const std::st * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation gdm_remove_sync(snowflake channel_id, snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation gdm_remove_sync(snowflake channel_id, snowflake user_id); /** * @brief Create single emoji. @@ -812,10 +864,11 @@ confirmation gdm_remove_sync(snowflake channel_id, snowflake user_id); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji guild_emoji_create_sync(snowflake guild_id, const class emoji& newemoji); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji guild_emoji_create_sync(snowflake guild_id, const class emoji& newemoji); /** * @brief Delete a guild emoji @@ -828,10 +881,11 @@ emoji guild_emoji_create_sync(snowflake guild_id, const class emoji& newemoji); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_emoji_delete_sync(snowflake guild_id, snowflake emoji_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_emoji_delete_sync(snowflake guild_id, snowflake emoji_id); /** * @brief Edit a single emoji. @@ -845,10 +899,11 @@ confirmation guild_emoji_delete_sync(snowflake guild_id, snowflake emoji_id); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji guild_emoji_edit_sync(snowflake guild_id, const class emoji& newemoji); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji guild_emoji_edit_sync(snowflake guild_id, const class emoji& newemoji); /** * @brief Get a single emoji @@ -860,10 +915,11 @@ emoji guild_emoji_edit_sync(snowflake guild_id, const class emoji& newemoji); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji guild_emoji_get_sync(snowflake guild_id, snowflake emoji_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji guild_emoji_get_sync(snowflake guild_id, snowflake emoji_id); /** * @brief Get all emojis for a guild @@ -874,10 +930,11 @@ emoji guild_emoji_get_sync(snowflake guild_id, snowflake emoji_id); * @return emoji_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji_map guild_emojis_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji_map guild_emojis_get_sync(snowflake guild_id); /** * @brief List all Application Emojis @@ -887,10 +944,11 @@ emoji_map guild_emojis_get_sync(snowflake guild_id); * @return emoji_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji_map application_emojis_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji_map application_emojis_get_sync(); /** * @brief Get an Application Emoji @@ -901,10 +959,11 @@ emoji_map application_emojis_get_sync(); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji application_emoji_get_sync(snowflake emoji_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji application_emoji_get_sync(snowflake emoji_id); /** * @brief Create an Application Emoji @@ -915,10 +974,11 @@ emoji application_emoji_get_sync(snowflake emoji_id); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji application_emoji_create_sync(const class emoji& newemoji); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji application_emoji_create_sync(const class emoji& newemoji); /** * @brief Edit an Application Emoji @@ -929,10 +989,11 @@ emoji application_emoji_create_sync(const class emoji& newemoji); * @return emoji returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji application_emoji_edit_sync(const class emoji& newemoji); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji application_emoji_edit_sync(const class emoji& newemoji); /** * @brief Delete an Application Emoji @@ -943,10 +1004,11 @@ emoji application_emoji_edit_sync(const class emoji& newemoji); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation application_emoji_delete_sync(snowflake emoji_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation application_emoji_delete_sync(snowflake emoji_id); /** * @brief Returns all entitlements for a given app, active and expired. @@ -963,10 +1025,11 @@ confirmation application_emoji_delete_sync(snowflake emoji_id); * @return entitlement_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -entitlement_map entitlements_get_sync(snowflake user_id = 0, const std::vector& sku_ids = {}, snowflake before_id = 0, snowflake after_id = 0, uint8_t limit = 100, snowflake guild_id = 0, bool exclude_ended = false); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") entitlement_map entitlements_get_sync(snowflake user_id = 0, const std::vector& sku_ids = {}, snowflake before_id = 0, snowflake after_id = 0, uint8_t limit = 100, snowflake guild_id = 0, bool exclude_ended = false); /** * @brief Creates a test entitlement to a given SKU for a given guild or user. @@ -980,10 +1043,11 @@ entitlement_map entitlements_get_sync(snowflake user_id = 0, const std::vector &message_ids, snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_bulk_sync(const std::vector &message_ids, snowflake channel_id); /** * @brief Delete a message from a channel. The callback function is called when the message has been edited @@ -1839,10 +1951,11 @@ confirmation message_delete_bulk_sync(const std::vector &message_ids, * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_sync(snowflake message_id, snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_sync(snowflake message_id, snowflake channel_id); /** * @brief Delete own reaction from a message. The reaction string must be either an `emojiname:id` or a unicode character. @@ -1854,10 +1967,11 @@ confirmation message_delete_sync(snowflake message_id, snowflake channel_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_own_reaction_sync(const struct message &m, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_own_reaction_sync(const struct message &m, const std::string &reaction); /** * @brief Delete own reaction from a message by id. The reaction string must be either an `emojiname:id` or a unicode character. @@ -1870,10 +1984,11 @@ confirmation message_delete_own_reaction_sync(const struct message &m, const std * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_own_reaction_sync(snowflake message_id, snowflake channel_id, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_own_reaction_sync(snowflake message_id, snowflake channel_id, const std::string &reaction); /** * @brief Delete a user's reaction from a message. The reaction string must be either an `emojiname:id` or a unicode character @@ -1886,10 +2001,11 @@ confirmation message_delete_own_reaction_sync(snowflake message_id, snowflake ch * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_reaction_sync(const struct message &m, snowflake user_id, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_reaction_sync(const struct message &m, snowflake user_id, const std::string &reaction); /** * @brief Delete a user's reaction from a message by id. The reaction string must be either an `emojiname:id` or a unicode character @@ -1903,10 +2019,11 @@ confirmation message_delete_reaction_sync(const struct message &m, snowflake use * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_reaction_sync(snowflake message_id, snowflake channel_id, snowflake user_id, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_reaction_sync(snowflake message_id, snowflake channel_id, snowflake user_id, const std::string &reaction); /** * @brief Delete all reactions on a message using a particular emoji. The reaction string must be either an `emojiname:id` or a unicode character @@ -1918,10 +2035,11 @@ confirmation message_delete_reaction_sync(snowflake message_id, snowflake channe * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_reaction_emoji_sync(const struct message &m, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_reaction_emoji_sync(const struct message &m, const std::string &reaction); /** * @brief Delete all reactions on a message using a particular emoji by id. The reaction string must be either an `emojiname:id` or a unicode character @@ -1934,10 +2052,11 @@ confirmation message_delete_reaction_emoji_sync(const struct message &m, const s * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_delete_reaction_emoji_sync(snowflake message_id, snowflake channel_id, const std::string &reaction); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_delete_reaction_emoji_sync(snowflake message_id, snowflake channel_id, const std::string &reaction); /** * @brief Edit a message on a channel. The callback function is called when the message has been edited @@ -1948,10 +2067,11 @@ confirmation message_delete_reaction_emoji_sync(snowflake message_id, snowflake * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message message_edit_sync(const struct message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message message_edit_sync(const struct message &m); /** * @brief Edit the flags of a message on a channel. The callback function is called when the message has been edited @@ -1960,10 +2080,11 @@ message message_edit_sync(const struct message &m); * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message message_edit_flags_sync(const struct message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message message_edit_flags_sync(const struct message &m); /** * @brief Get a message @@ -1975,10 +2096,11 @@ message message_edit_flags_sync(const struct message &m); * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message message_get_sync(snowflake message_id, snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message message_get_sync(snowflake message_id, snowflake channel_id); /** * @brief Get reactions on a message for a particular emoji. The reaction string must be either an `emojiname:id` or a unicode character @@ -1993,10 +2115,11 @@ message message_get_sync(snowflake message_id, snowflake channel_id); * @return user_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_map message_get_reactions_sync(const struct message &m, const std::string &reaction, snowflake before, snowflake after, snowflake limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_map message_get_reactions_sync(const struct message &m, const std::string &reaction, snowflake before, snowflake after, snowflake limit); /** * @brief Get reactions on a message for a particular emoji by id. The reaction string must be either an `emojiname:id` or a unicode character @@ -2012,10 +2135,11 @@ user_map message_get_reactions_sync(const struct message &m, const std::string & * @return emoji_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -emoji_map message_get_reactions_sync(snowflake message_id, snowflake channel_id, const std::string &reaction, snowflake before, snowflake after, snowflake limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") emoji_map message_get_reactions_sync(snowflake message_id, snowflake channel_id, const std::string &reaction, snowflake before, snowflake after, snowflake limit); /** * @brief Pin a message @@ -2027,10 +2151,11 @@ emoji_map message_get_reactions_sync(snowflake message_id, snowflake channel_id, * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_pin_sync(snowflake channel_id, snowflake message_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_pin_sync(snowflake channel_id, snowflake message_id); /** * @brief Get multiple messages. @@ -2047,10 +2172,11 @@ confirmation message_pin_sync(snowflake channel_id, snowflake message_id); * @return message_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message_map messages_get_sync(snowflake channel_id, snowflake around, snowflake before, snowflake after, uint64_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message_map messages_get_sync(snowflake channel_id, snowflake around, snowflake before, snowflake after, uint64_t limit); /** * @brief Unpin a message @@ -2062,10 +2188,11 @@ message_map messages_get_sync(snowflake channel_id, snowflake around, snowflake * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation message_unpin_sync(snowflake channel_id, snowflake message_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation message_unpin_sync(snowflake channel_id, snowflake message_id); /** * @brief Get a list of users that voted for this specific answer. @@ -2079,10 +2206,11 @@ confirmation message_unpin_sync(snowflake channel_id, snowflake message_id); * @see https://discord.com/developers/docs/resources/poll#get-answer-voters * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_map poll_get_answer_voters_sync(const message& m, uint32_t answer_id, snowflake after, uint64_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_map poll_get_answer_voters_sync(const message& m, uint32_t answer_id, snowflake after, uint64_t limit); /** * @brief Get a list of users that voted for this specific answer. @@ -2097,10 +2225,11 @@ user_map poll_get_answer_voters_sync(const message& m, uint32_t answer_id, snowf * @see https://discord.com/developers/docs/resources/poll#get-answer-voters * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_map poll_get_answer_voters_sync(snowflake message_id, snowflake channel_id, uint32_t answer_id, snowflake after, uint64_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_map poll_get_answer_voters_sync(snowflake message_id, snowflake channel_id, uint32_t answer_id, snowflake after, uint64_t limit); /** * @brief Immediately end a poll. @@ -2111,10 +2240,11 @@ user_map poll_get_answer_voters_sync(snowflake message_id, snowflake channel_id, * @see https://discord.com/developers/docs/resources/poll#end-poll * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message poll_end_sync(const message &m); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message poll_end_sync(const message &m); /** * @brief Immediately end a poll. @@ -2126,10 +2256,11 @@ message poll_end_sync(const message &m); * @see https://discord.com/developers/docs/resources/poll#end-poll * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message poll_end_sync(snowflake message_id, snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message poll_end_sync(snowflake message_id, snowflake channel_id); /** * @brief Get a channel's pins @@ -2139,10 +2270,11 @@ message poll_end_sync(snowflake message_id, snowflake channel_id); * @return message_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message_map channel_pins_get_sync(snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message_map channel_pins_get_sync(snowflake channel_id); /** * @brief Create a role on a guild @@ -2157,10 +2289,11 @@ message_map channel_pins_get_sync(snowflake channel_id); * @return role returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -role role_create_sync(const class role &r); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") role role_create_sync(const class role &r); /** * @brief Delete a role @@ -2175,10 +2308,11 @@ role role_create_sync(const class role &r); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation role_delete_sync(snowflake guild_id, snowflake role_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation role_delete_sync(snowflake guild_id, snowflake role_id); /** * @brief Edit a role on a guild @@ -2192,10 +2326,11 @@ confirmation role_delete_sync(snowflake guild_id, snowflake role_id); * @return role returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -role role_edit_sync(const class role &r); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") role role_edit_sync(const class role &r); /** * @brief Edit multiple role's position in a guild. Returns a list of all roles of the guild on success. @@ -2211,10 +2346,11 @@ role role_edit_sync(const class role &r); * @return role_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -role_map roles_edit_position_sync(snowflake guild_id, const std::vector &roles); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") role_map roles_edit_position_sync(snowflake guild_id, const std::vector &roles); /** * @brief Get a role for a guild @@ -2225,10 +2361,11 @@ role_map roles_edit_position_sync(snowflake guild_id, const std::vector &r * @return role_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -role_map roles_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") role_map roles_get_sync(snowflake guild_id); /** * @brief Get the application's role connection metadata records @@ -2239,10 +2376,11 @@ role_map roles_get_sync(snowflake guild_id); * @return application_role_connection returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -application_role_connection application_role_connection_get_sync(snowflake application_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") application_role_connection application_role_connection_get_sync(snowflake application_id); /** * @brief Update the application's role connection metadata records @@ -2255,10 +2393,11 @@ application_role_connection application_role_connection_get_sync(snowflake appli * @note An application can have a maximum of 5 metadata records. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -application_role_connection application_role_connection_update_sync(snowflake application_id, const std::vector &connection_metadata); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") application_role_connection application_role_connection_update_sync(snowflake application_id, const std::vector &connection_metadata); /** * @brief Get user application role connection @@ -2269,10 +2408,11 @@ application_role_connection application_role_connection_update_sync(snowflake ap * @return application_role_connection returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -application_role_connection user_application_role_connection_get_sync(snowflake application_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") application_role_connection user_application_role_connection_get_sync(snowflake application_id); /** * @brief Update user application role connection @@ -2284,10 +2424,11 @@ application_role_connection user_application_role_connection_get_sync(snowflake * @return application_role_connection returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -application_role_connection user_application_role_connection_update_sync(snowflake application_id, const application_role_connection &connection); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") application_role_connection user_application_role_connection_update_sync(snowflake application_id, const application_role_connection &connection); /** * @brief Get all scheduled events for a guild @@ -2297,10 +2438,11 @@ application_role_connection user_application_role_connection_update_sync(snowfla * @return scheduled_event_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -scheduled_event_map guild_events_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") scheduled_event_map guild_events_get_sync(snowflake guild_id); /** * @brief Create a scheduled event on a guild @@ -2311,10 +2453,11 @@ scheduled_event_map guild_events_get_sync(snowflake guild_id); * @return scheduled_event returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -scheduled_event guild_event_create_sync(const scheduled_event& event); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") scheduled_event guild_event_create_sync(const scheduled_event& event); /** * @brief Delete a scheduled event from a guild @@ -2326,10 +2469,11 @@ scheduled_event guild_event_create_sync(const scheduled_event& event); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_event_delete_sync(snowflake event_id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_event_delete_sync(snowflake event_id, snowflake guild_id); /** * @brief Edit/modify a scheduled event on a guild @@ -2340,10 +2484,11 @@ confirmation guild_event_delete_sync(snowflake event_id, snowflake guild_id); * @return scheduled_event returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -scheduled_event guild_event_edit_sync(const scheduled_event& event); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") scheduled_event guild_event_edit_sync(const scheduled_event& event); /** * @brief Get a scheduled event for a guild @@ -2355,10 +2500,11 @@ scheduled_event guild_event_edit_sync(const scheduled_event& event); * @return scheduled_event returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -scheduled_event guild_event_get_sync(snowflake guild_id, snowflake event_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") scheduled_event guild_event_get_sync(snowflake guild_id, snowflake event_id); /** * @brief Returns all SKUs for a given application. @@ -2370,13 +2516,14 @@ scheduled_event guild_event_get_sync(snowflake guild_id, snowflake event_id); * @return sku_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sku_map skus_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sku_map skus_get_sync(); -stage_instance stage_instance_create_sync(const stage_instance& si); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") stage_instance stage_instance_create_sync(const stage_instance& si); /** * @brief Get the stage instance associated with the channel id, if it exists. @@ -2386,13 +2533,14 @@ stage_instance stage_instance_create_sync(const stage_instance& si); * @return stage_instance returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -stage_instance stage_instance_get_sync(const snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") stage_instance stage_instance_get_sync(const snowflake channel_id); -stage_instance stage_instance_edit_sync(const stage_instance& si); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") stage_instance stage_instance_edit_sync(const stage_instance& si); /** * @brief Delete a stage instance. @@ -2403,10 +2551,11 @@ stage_instance stage_instance_edit_sync(const stage_instance& si); * @note This method supports audit log reasons set by the cluster::set_audit_reason() method. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation stage_instance_delete_sync(const snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation stage_instance_delete_sync(const snowflake channel_id); /** * @brief Create a sticker in a guild @@ -2417,10 +2566,11 @@ confirmation stage_instance_delete_sync(const snowflake channel_id); * @return sticker returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker guild_sticker_create_sync(const sticker &s); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker guild_sticker_create_sync(const sticker &s); /** * @brief Delete a sticker from a guild @@ -2432,10 +2582,11 @@ sticker guild_sticker_create_sync(const sticker &s); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_sticker_delete_sync(snowflake sticker_id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_sticker_delete_sync(snowflake sticker_id, snowflake guild_id); /** * @brief Get a guild sticker @@ -2446,10 +2597,11 @@ confirmation guild_sticker_delete_sync(snowflake sticker_id, snowflake guild_id) * @return sticker returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker guild_sticker_get_sync(snowflake id, snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker guild_sticker_get_sync(snowflake id, snowflake guild_id); /** * @brief Modify a sticker in a guild @@ -2460,10 +2612,11 @@ sticker guild_sticker_get_sync(snowflake id, snowflake guild_id); * @return sticker returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker guild_sticker_modify_sync(const sticker &s); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker guild_sticker_modify_sync(const sticker &s); /** * @brief Get all guild stickers @@ -2473,10 +2626,11 @@ sticker guild_sticker_modify_sync(const sticker &s); * @return sticker_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker_map guild_stickers_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker_map guild_stickers_get_sync(snowflake guild_id); /** * @brief Get a nitro sticker @@ -2486,10 +2640,11 @@ sticker_map guild_stickers_get_sync(snowflake guild_id); * @return sticker returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker nitro_sticker_get_sync(snowflake id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker nitro_sticker_get_sync(snowflake id); /** * @brief Get a list of available sticker packs @@ -2498,10 +2653,11 @@ sticker nitro_sticker_get_sync(snowflake id); * @return sticker_pack_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -sticker_pack_map sticker_packs_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") sticker_pack_map sticker_packs_get_sync(); /** * @brief Create a new guild based on a template. @@ -2513,10 +2669,11 @@ sticker_pack_map sticker_packs_get_sync(); * @return guild returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -guild guild_create_from_template_sync(const std::string &code, const std::string &name); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") guild guild_create_from_template_sync(const std::string &code, const std::string &name); /** * @brief Creates a template for the guild @@ -2529,10 +2686,11 @@ guild guild_create_from_template_sync(const std::string &code, const std::string * @return dtemplate returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -dtemplate guild_template_create_sync(snowflake guild_id, const std::string &name, const std::string &description); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") dtemplate guild_template_create_sync(snowflake guild_id, const std::string &name, const std::string &description); /** * @brief Deletes the template @@ -2544,10 +2702,11 @@ dtemplate guild_template_create_sync(snowflake guild_id, const std::string &name * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation guild_template_delete_sync(snowflake guild_id, const std::string &code); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation guild_template_delete_sync(snowflake guild_id, const std::string &code); /** * @brief Modifies the template's metadata. @@ -2561,10 +2720,11 @@ confirmation guild_template_delete_sync(snowflake guild_id, const std::string &c * @return dtemplate returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -dtemplate guild_template_modify_sync(snowflake guild_id, const std::string &code, const std::string &name, const std::string &description); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") dtemplate guild_template_modify_sync(snowflake guild_id, const std::string &code, const std::string &name, const std::string &description); /** * @brief Get guild templates @@ -2575,10 +2735,11 @@ dtemplate guild_template_modify_sync(snowflake guild_id, const std::string &code * @return dtemplate_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -dtemplate_map guild_templates_get_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") dtemplate_map guild_templates_get_sync(snowflake guild_id); /** * @brief Syncs the template to the guild's current state. @@ -2590,10 +2751,11 @@ dtemplate_map guild_templates_get_sync(snowflake guild_id); * @return dtemplate returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -dtemplate guild_template_sync_sync(snowflake guild_id, const std::string &code); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") dtemplate guild_template_sync_sync(snowflake guild_id, const std::string &code); /** * @brief Get a template @@ -2603,10 +2765,11 @@ dtemplate guild_template_sync_sync(snowflake guild_id, const std::string &code); * @return dtemplate returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -dtemplate template_get_sync(const std::string &code); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") dtemplate template_get_sync(const std::string &code); /** * @brief Join a thread @@ -2616,10 +2779,11 @@ dtemplate template_get_sync(const std::string &code); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation current_user_join_thread_sync(snowflake thread_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation current_user_join_thread_sync(snowflake thread_id); /** * @brief Leave a thread @@ -2629,10 +2793,11 @@ confirmation current_user_join_thread_sync(snowflake thread_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation current_user_leave_thread_sync(snowflake thread_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation current_user_leave_thread_sync(snowflake thread_id); /** * @brief Get all active threads in the guild, including public and private threads. Threads are ordered by their id, in descending order. @@ -2642,10 +2807,11 @@ confirmation current_user_leave_thread_sync(snowflake thread_id); * @return active_threads returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -active_threads threads_get_active_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") active_threads threads_get_active_sync(snowflake guild_id); /** * @brief Get private archived threads in a channel which current user has joined (Sorted by ID in descending order) @@ -2657,10 +2823,11 @@ active_threads threads_get_active_sync(snowflake guild_id); * @return thread_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread_map threads_get_joined_private_archived_sync(snowflake channel_id, snowflake before_id, uint16_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread_map threads_get_joined_private_archived_sync(snowflake channel_id, snowflake before_id, uint16_t limit); /** * @brief Get private archived threads in a channel (Sorted by archive_timestamp in descending order) @@ -2672,10 +2839,11 @@ thread_map threads_get_joined_private_archived_sync(snowflake channel_id, snowfl * @return thread_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread_map threads_get_private_archived_sync(snowflake channel_id, time_t before_timestamp, uint16_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread_map threads_get_private_archived_sync(snowflake channel_id, time_t before_timestamp, uint16_t limit); /** * @brief Get public archived threads in a channel (Sorted by archive_timestamp in descending order) @@ -2687,10 +2855,11 @@ thread_map threads_get_private_archived_sync(snowflake channel_id, time_t befor * @return thread_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread_map threads_get_public_archived_sync(snowflake channel_id, time_t before_timestamp, uint16_t limit); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread_map threads_get_public_archived_sync(snowflake channel_id, time_t before_timestamp, uint16_t limit); /** * @brief Get a thread member @@ -2701,10 +2870,11 @@ thread_map threads_get_public_archived_sync(snowflake channel_id, time_t before_ * @return thread_member returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread_member thread_member_get_sync(const snowflake thread_id, const snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread_member thread_member_get_sync(const snowflake thread_id, const snowflake user_id); /** * @brief Get members of a thread @@ -2714,10 +2884,11 @@ thread_member thread_member_get_sync(const snowflake thread_id, const snowflake * @return thread_member_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread_member_map thread_members_get_sync(snowflake thread_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread_member_map thread_members_get_sync(snowflake thread_id); /** * @brief Create a thread in a forum or media channel @@ -2734,10 +2905,11 @@ thread_member_map thread_members_get_sync(snowflake thread_id); * @return thread returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread thread_create_in_forum_sync(const std::string& thread_name, snowflake channel_id, const message& msg, auto_archive_duration_t auto_archive_duration, uint16_t rate_limit_per_user, std::vector applied_tags = {}); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread thread_create_in_forum_sync(const std::string& thread_name, snowflake channel_id, const message& msg, auto_archive_duration_t auto_archive_duration, uint16_t rate_limit_per_user, std::vector applied_tags = {}); /** * @brief Create a thread @@ -2754,10 +2926,11 @@ thread thread_create_in_forum_sync(const std::string& thread_name, snowflake cha * @return thread returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread thread_create_sync(const std::string& thread_name, snowflake channel_id, uint16_t auto_archive_duration, channel_type thread_type, bool invitable, uint16_t rate_limit_per_user); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread thread_create_sync(const std::string& thread_name, snowflake channel_id, uint16_t auto_archive_duration, channel_type thread_type, bool invitable, uint16_t rate_limit_per_user); /** * @brief Edit a thread @@ -2769,10 +2942,11 @@ thread thread_create_sync(const std::string& thread_name, snowflake channel_id, * @return thread returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread thread_edit_sync(const thread &t); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread thread_edit_sync(const thread &t); /** * @brief Create a thread with a message (Discord: ID of a thread is same as message ID) @@ -2787,10 +2961,11 @@ thread thread_edit_sync(const thread &t); * @return thread returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread thread_create_with_message_sync(const std::string& thread_name, snowflake channel_id, snowflake message_id, uint16_t auto_archive_duration, uint16_t rate_limit_per_user); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread thread_create_with_message_sync(const std::string& thread_name, snowflake channel_id, snowflake message_id, uint16_t auto_archive_duration, uint16_t rate_limit_per_user); /** * @brief Add a member to a thread @@ -2801,10 +2976,11 @@ thread thread_create_with_message_sync(const std::string& thread_name, snowflake * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation thread_member_add_sync(snowflake thread_id, snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation thread_member_add_sync(snowflake thread_id, snowflake user_id); /** * @brief Remove a member from a thread @@ -2815,10 +2991,11 @@ confirmation thread_member_add_sync(snowflake thread_id, snowflake user_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation thread_member_remove_sync(snowflake thread_id, snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation thread_member_remove_sync(snowflake thread_id, snowflake user_id); /** * @brief Get the thread specified by thread_id. This uses the same call as dpp::cluster::channel_get but returns a thread object. @@ -2828,10 +3005,11 @@ confirmation thread_member_remove_sync(snowflake thread_id, snowflake user_id); * @return thread returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -thread thread_get_sync(snowflake thread_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") thread thread_get_sync(snowflake thread_id); /** * @brief Edit current (bot) user. @@ -2852,10 +3030,11 @@ thread thread_get_sync(snowflake thread_id); * @throw dpp::length_exception Image data is larger than the maximum size of 256 kilobytes * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user current_user_edit_sync(const std::string &nickname, const std::string& avatar_blob = "", const image_type avatar_type = i_png, const std::string& banner_blob = "", const image_type banner_type = i_png); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user current_user_edit_sync(const std::string &nickname, const std::string& avatar_blob = "", const image_type avatar_type = i_png, const std::string& banner_blob = "", const image_type banner_type = i_png); /** * @brief Get current (bot) application @@ -2865,10 +3044,11 @@ user current_user_edit_sync(const std::string &nickname, const std::string& avat * @return application returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -application current_application_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") application current_application_get_sync(); /** * @brief Get current (bot) user @@ -2880,10 +3060,11 @@ application current_application_get_sync(); * If you do not have these scopes, these fields are empty. You can safely convert a user_identified to user with `dynamic_cast`. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_identified current_user_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_identified current_user_get_sync(); /** * @brief Set the bot's voice state on a stage channel @@ -2908,10 +3089,11 @@ user_identified current_user_get_sync(); * @throw std::logic_exception You attempted to set a request_to_speak_timestamp in the past which is not the value of 0. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation current_user_set_voice_state_sync(snowflake guild_id, snowflake channel_id, bool suppress = false, time_t request_to_speak_timestamp = 0); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation current_user_set_voice_state_sync(snowflake guild_id, snowflake channel_id, bool suppress = false, time_t request_to_speak_timestamp = 0); /** * @brief Set a user's voice state on a stage channel @@ -2935,10 +3117,11 @@ confirmation current_user_set_voice_state_sync(snowflake guild_id, snowflake cha * @param suppress True if the user's audio should be suppressed, false if it should not * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation user_set_voice_state_sync(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress = false); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation user_set_voice_state_sync(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress = false); /** * @brief Get current user's connections (linked accounts, e.g. steam, xbox). @@ -2949,10 +3132,11 @@ confirmation user_set_voice_state_sync(snowflake user_id, snowflake guild_id, sn * @return connection_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -connection_map current_user_connections_get_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") connection_map current_user_connections_get_sync(); /** * @brief Get current (bot) user guilds @@ -2961,10 +3145,11 @@ connection_map current_user_connections_get_sync(); * @return guild_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -guild_map current_user_get_guilds_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") guild_map current_user_get_guilds_sync(); /** * @brief Leave a guild @@ -2974,10 +3159,11 @@ guild_map current_user_get_guilds_sync(); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation current_user_leave_guild_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation current_user_leave_guild_sync(snowflake guild_id); /** * @brief Get a user by id, without using the cache @@ -2992,10 +3178,11 @@ confirmation current_user_leave_guild_sync(snowflake guild_id); * Call `dpp::find_user` instead that looks up the user in the cache rather than a REST call. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_identified user_get_sync(snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_identified user_get_sync(snowflake user_id); /** * @brief Get a user by id, checking in the cache first @@ -3010,10 +3197,11 @@ user_identified user_get_sync(snowflake user_id); * where you want to for example resolve a user who may no longer be in the bot's guilds, for something like a ban log message. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -user_identified user_get_cached_sync(snowflake user_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") user_identified user_get_cached_sync(snowflake user_id); /** * @brief Get all voice regions @@ -3022,10 +3210,11 @@ user_identified user_get_cached_sync(snowflake user_id); * @return voiceregion_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -voiceregion_map get_voice_regions_sync(); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") voiceregion_map get_voice_regions_sync(); /** * @brief Get guild voice regions. @@ -3040,13 +3229,14 @@ voiceregion_map get_voice_regions_sync(); * @return voiceregion_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -voiceregion_map guild_get_voice_regions_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") voiceregion_map guild_get_voice_regions_sync(snowflake guild_id); -webhook create_webhook_sync(const class webhook &wh); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook create_webhook_sync(const class webhook &wh); /** * @brief Delete a webhook @@ -3057,10 +3247,11 @@ webhook create_webhook_sync(const class webhook &wh); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation delete_webhook_sync(snowflake webhook_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation delete_webhook_sync(snowflake webhook_id); /** * @brief Delete webhook message @@ -3073,10 +3264,11 @@ confirmation delete_webhook_sync(snowflake webhook_id); * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation delete_webhook_message_sync(const class webhook &wh, snowflake message_id, snowflake thread_id = 0); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation delete_webhook_message_sync(const class webhook &wh, snowflake message_id, snowflake thread_id = 0); /** * @brief Delete webhook with token @@ -3087,10 +3279,11 @@ confirmation delete_webhook_message_sync(const class webhook &wh, snowflake mess * @return confirmation returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -confirmation delete_webhook_with_token_sync(snowflake webhook_id, const std::string &token); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation delete_webhook_with_token_sync(snowflake webhook_id, const std::string &token); /** * @brief Edit webhook @@ -3101,10 +3294,11 @@ confirmation delete_webhook_with_token_sync(snowflake webhook_id, const std::str * @return webhook returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook edit_webhook_sync(const class webhook& wh); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook edit_webhook_sync(const class webhook& wh); /** * @brief Edit webhook message @@ -3123,10 +3317,11 @@ webhook edit_webhook_sync(const class webhook& wh); * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message edit_webhook_message_sync(const class webhook &wh, const struct message &m, snowflake thread_id = 0); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message edit_webhook_message_sync(const class webhook &wh, const struct message &m, snowflake thread_id = 0); /** * @brief Edit webhook with token (token is encapsulated in the webhook object) @@ -3136,10 +3331,11 @@ message edit_webhook_message_sync(const class webhook &wh, const struct message * @return webhook returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook edit_webhook_with_token_sync(const class webhook& wh); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook edit_webhook_with_token_sync(const class webhook& wh); /** * @brief Execute webhook @@ -3155,10 +3351,11 @@ webhook edit_webhook_with_token_sync(const class webhook& wh); * @note If the webhook channel is a forum channel, you must provide either `thread_id` or `thread_name`. If `thread_id` is provided, the message will send in that thread. If `thread_name` is provided, a thread with that name will be created in the forum channel. * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message execute_webhook_sync(const class webhook &wh, const struct message &m, bool wait = false, snowflake thread_id = 0, const std::string& thread_name = ""); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message execute_webhook_sync(const class webhook &wh, const struct message &m, bool wait = false, snowflake thread_id = 0, const std::string& thread_name = ""); /** * @brief Get channel webhooks @@ -3168,10 +3365,11 @@ message execute_webhook_sync(const class webhook &wh, const struct message &m, b * @return webhook_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook_map get_channel_webhooks_sync(snowflake channel_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook_map get_channel_webhooks_sync(snowflake channel_id); /** * @brief Get guild webhooks @@ -3181,10 +3379,11 @@ webhook_map get_channel_webhooks_sync(snowflake channel_id); * @return webhook_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook_map get_guild_webhooks_sync(snowflake guild_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook_map get_guild_webhooks_sync(snowflake guild_id); /** * @brief Get webhook @@ -3194,10 +3393,11 @@ webhook_map get_guild_webhooks_sync(snowflake guild_id); * @return webhook returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook get_webhook_sync(snowflake webhook_id); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook get_webhook_sync(snowflake webhook_id); /** * @brief Get webhook message @@ -3210,10 +3410,11 @@ webhook get_webhook_sync(snowflake webhook_id); * @return message returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -message get_webhook_message_sync(const class webhook &wh, snowflake message_id, snowflake thread_id = 0); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") message get_webhook_message_sync(const class webhook &wh, snowflake message_id, snowflake thread_id = 0); /** * @brief Get webhook using token @@ -3224,10 +3425,11 @@ message get_webhook_message_sync(const class webhook &wh, snowflake message_id, * @return webhook returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. * Avoid direct use of this function inside an event handler. */ -webhook get_webhook_with_token_sync(snowflake webhook_id, const std::string &token); +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") webhook get_webhook_with_token_sync(snowflake webhook_id, const std::string &token); /* End of auto-generated definitions */ diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 1af1301003..7c61570ab7 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -2052,7 +2052,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b .set_user_limit(99); dpp::channel createdChannel; try { - createdChannel = bot.channel_create_sync(channel1); + createdChannel = dpp::sync(&bot, &dpp::cluster::channel_create, channel1); } catch (dpp::rest_exception &exception) { set_test(VOICE_CHANNEL_CREATE, false); } @@ -2075,7 +2075,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b } } try { - dpp::channel edited = bot.channel_edit_sync(createdChannel); + dpp::channel edited = dpp::sync(&bot, &dpp::cluster::channel_edit, createdChannel); if (edited.name == "foobar2" && edited.user_limit == 2) { set_test(VOICE_CHANNEL_EDIT, true); } @@ -2085,9 +2085,10 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b // delete the voice channel try { - bot.channel_delete_sync(createdChannel.id); + dpp::sync(&bot, &dpp::cluster::channel_delete, createdChannel.id); set_test(VOICE_CHANNEL_DELETE, true); } catch (dpp::rest_exception &exception) { + bot.log(dpp::ll_warning, "Exception: " + std::string(exception.what())); set_test(VOICE_CHANNEL_DELETE, false); } } @@ -2280,7 +2281,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b r.colour = dpp::colors::moon_yellow; dpp::role createdRole; try { - createdRole = bot.role_create_sync(r); + createdRole = dpp::sync(&bot, &dpp::cluster::role_create, r); if (createdRole.name == r.name && createdRole.has_move_members() && createdRole.flags & dpp::r_mentionable && @@ -2294,7 +2295,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b createdRole.name = "Test-Role-Edited"; createdRole.colour = dpp::colors::light_sea_green; try { - dpp::role edited = bot.role_edit_sync(createdRole); + dpp::role edited = dpp::sync(&bot, &dpp::cluster::role_edit, createdRole); if (createdRole.id == edited.id && edited.name == "Test-Role-Edited") { set_test(ROLE_EDIT, true); } @@ -2302,9 +2303,10 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test(ROLE_EDIT, false); } try { - bot.role_delete_sync(TEST_GUILD_ID, createdRole.id); + dpp::sync(&bot, &dpp::cluster::role_delete, TEST_GUILD_ID, createdRole.id); set_test(ROLE_DELETE, true); } catch (dpp::rest_exception &exception) { + bot.log(dpp::ll_warning, "Exception: " + std::string(exception.what())); set_test(ROLE_DELETE, false); } } @@ -2335,7 +2337,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b set_test(USER_GET_CACHED_PRESENT, false); try { - dpp::user_identified u = bot.user_get_cached_sync(TEST_USER_ID); + dpp::user_identified u = dpp::sync(&bot, &dpp::cluster::user_get_cached, TEST_USER_ID); set_test(USER_GET_CACHED_PRESENT, (u.id == TEST_USER_ID)); } catch (const std::exception&) { @@ -2350,7 +2352,7 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b * If this becomes not true any more, we'll pick another well known * user ID. */ - dpp::user_identified u = bot.user_get_cached_sync(90339695967350784); + dpp::user_identified u = dpp::sync(&bot, &dpp::cluster::user_get_cached, 90339695967350784); set_test(USER_GET_CACHED_ABSENT, (u.id == dpp::snowflake(90339695967350784))); } catch (const std::exception&) { From 4965b5c5917d1db022c0bdb927ee945a2c37e1a6 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 16 Oct 2024 08:30:47 +0100 Subject: [PATCH 75/99] refactor: low level socket tidyups and removal of punning (#1282) --- .cspell.json | 3 +- include/dpp/discordvoiceclient.h | 7 ++ include/dpp/dns.h | 37 ++++-- include/dpp/socket.h | 135 ++++++++++++++++++++- src/dpp/dns.cpp | 155 +++++++++++++++---------- src/dpp/socket.cpp | 63 ++++++++++ src/dpp/sslclient.cpp | 6 +- src/dpp/voice/enabled/discover_ip.cpp | 28 +---- src/dpp/voice/enabled/handle_frame.cpp | 19 +-- src/dpp/voice/enabled/read_write.cpp | 17 ++- 10 files changed, 342 insertions(+), 128 deletions(-) create mode 100644 src/dpp/socket.cpp diff --git a/.cspell.json b/.cspell.json index 3cfb280732..0d8e2cd969 100644 --- a/.cspell.json +++ b/.cspell.json @@ -148,7 +148,8 @@ "nullopt", "chrono", "ciphersuite", - "rmap" + "rmap", + "WSAPOLLFD" ], "flagWords": [ "hte" diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 6ce21bf309..658ba6422a 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -584,6 +584,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ dave_version_t dave_version; + /** + * @brief Destination address for where packets go + * on the UDP socket + */ + address_t destination{}; + + /** * @brief Send data to UDP socket immediately. * diff --git a/include/dpp/dns.h b/include/dpp/dns.h index 5a3a566d45..48cebcd563 100644 --- a/include/dpp/dns.h +++ b/include/dpp/dns.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include namespace dpp { @@ -40,23 +42,42 @@ namespace dpp { */ struct dns_cache_entry { /** - * @brief Resolved address information + * @brief Resolved address metadata */ addrinfo addr; /** - * @brief Socket address. - * Discord only supports ipv4, but sockaddr_in6 is larger - * than sockaddr_in, sockaddr_storage will hold either. This - * means that if discord ever do support ipv6 we just flip - * one value in dns.cpp and that should be all that is needed. + * @brief Resolved address as string. + * The metadata is needed to know what type of address it is. + * Do not do silly stuff like just looking to see if '.' is in it! */ - sockaddr_storage ai_addr; + std::string resolved_addr; /** * @brief Time at which this cache entry is invalidated */ time_t expire_timestamp; + + /** + * @brief Get address length + * @return address length + */ + [[nodiscard]] int size() const; + + /** + * @brief Get the address_t that corresponds to this cache entry + * for use when connecting with ::connect() + * @param port Port number to connect to + * @return address_t prefilled with the IP and port number + */ + [[nodiscard]] const address_t get_connecting_address(uint16_t port) const; + + /** + * @brief Allocate a socket file descriptor for the given dns address + * @return File descriptor ready for calling connect(), or INVALID_SOCKET + * on failure. + */ + [[nodiscard]] socket make_connecting_socket() const; }; /** @@ -73,4 +94,4 @@ namespace dpp { * @throw dpp::connection_exception On failure to resolve hostname */ const dns_cache_entry* resolve_hostname(const std::string& hostname, const std::string& port); -} // namespace dpp +} diff --git a/include/dpp/socket.h b/include/dpp/socket.h index d94914b35a..3888b2e022 100644 --- a/include/dpp/socket.h +++ b/include/dpp/socket.h @@ -1,17 +1,53 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ #pragma once +#include +#ifdef _WIN32 + #include + #include + #include + #define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout) + #define pollfd WSAPOLLFD +#else + #include + #include + #include +#endif +#include +#include + + namespace dpp { - /** - * @brief Represents a socket file descriptor. - * This is used to ensure parity between windows and unix-like systems. - */ +/** + * @brief Represents a socket file descriptor. + * This is used to ensure parity between windows and unix-like systems. + */ #ifndef _WIN32 using socket = int; #else using socket = SOCKET; #endif -} // namespace dpp #ifndef SOCKET_ERROR /** @@ -26,3 +62,92 @@ namespace dpp */ #define INVALID_SOCKET ~0 #endif + +/** + * @brief Represents an IPv4 address for use with socket functions such as + * bind(). + * + * Avoids type punning with C style casts from sockaddr_in to sockaddr pointers. + */ +class DPP_EXPORT address_t { + /** + * @brief Internal sockaddr struct + */ + sockaddr socket_addr{}; + +public: + + /** + * @brief Create a new address_t + * @param ip IPv4 address + * @param port Port number + * @note Leave both as defaults to create a default bind-to-any setting + */ + address_t(const std::string_view ip = "0.0.0.0", uint16_t port = 0); + + /** + * @brief Get sockaddr + * @return sockaddr pointer + */ + [[nodiscard]] sockaddr *get_socket_address(); + + /** + * @brief Returns size of sockaddr_in + * @return sockaddr_in size + * @note It is important the size this returns is sizeof(sockaddr_in) not + * sizeof(sockaddr), this is NOT a bug but requirement of C socket functions. + */ + [[nodiscard]] size_t size(); + + /** + * @brief Get the port bound to a file descriptor + * @param fd File descriptor + * @return Port number, or 0 if no port bound + */ + [[nodiscard]] uint16_t get_port(socket fd); +}; + +/** + * @brief Allocates a dpp::socket, closing it on destruction + */ +struct DPP_EXPORT raii_socket { + /** + * @brief File descriptor + */ + socket fd; + + /** + * @brief Construct a socket. + * Calls socket() and returns a new file descriptor + */ + raii_socket(); + + /** + * @brief Non-copyable + */ + raii_socket(raii_socket&) = delete; + + /** + * @brief Non-movable + */ + raii_socket(raii_socket&&) = delete; + + /** + * @brief Non-copyable + */ + raii_socket operator=(raii_socket&) = delete; + + /** + * @brief Non-movable + */ + raii_socket operator=(raii_socket&&) = delete; + + /** + * @brief Destructor + * Frees the socket by closing it + */ + ~raii_socket(); +}; + + +} diff --git a/src/dpp/dns.cpp b/src/dpp/dns.cpp index e87fbd45e8..257b9b2315 100644 --- a/src/dpp/dns.cpp +++ b/src/dpp/dns.cpp @@ -39,75 +39,102 @@ namespace dpp /* Cache container */ dns_cache_t dns_cache; - const dns_cache_entry* resolve_hostname(const std::string& hostname, const std::string& port) +/** +* @brief Get address length +* @return address length +*/ +int dns_cache_entry::size() const { + return static_cast(addr.ai_addrlen); +} + +const address_t dns_cache_entry::get_connecting_address(uint16_t port) const { + return address_t(resolved_addr, port); +} + +socket dns_cache_entry::make_connecting_socket() const { + return ::socket(addr.ai_family, addr.ai_socktype, addr.ai_protocol); +} + +const dns_cache_entry* resolve_hostname(const std::string& hostname, const std::string& port) +{ + addrinfo hints, *addrs; + dns_cache_t::const_iterator iter; + time_t now = time(nullptr); + int error; + bool exists = false; + + /* Thread safety scope */ { - addrinfo hints, *addrs; - dns_cache_t::const_iterator iter; - time_t now = time(nullptr); - int error; - bool exists = false; - - /* Thread safety scope */ - { - /* Check cache for existing DNS record. This can use a shared lock. */ - std::shared_lock dns_cache_lock(dns_cache_mutex); - iter = dns_cache.find(hostname); - if (iter != dns_cache.end()) { - exists = true; - if (now < iter->second->expire_timestamp) { - /* there is a cached entry that is still valid, return it */ - return iter->second; - } + /* Check cache for existing DNS record. This can use a shared lock. */ + std::shared_lock dns_cache_lock(dns_cache_mutex); + iter = dns_cache.find(hostname); + if (iter != dns_cache.end()) { + exists = true; + if (now < iter->second->expire_timestamp) { + /* there is a cached entry that is still valid, return it */ + return iter->second; } } - if (exists) { - /* there is a cached entry, but it has expired, - * delete and free it, and fall through to a new lookup. - * We must use a unique lock here as we modify the cache. - */ - std::unique_lock dns_cache_lock(dns_cache_mutex); - iter = dns_cache.find(hostname); - if (iter != dns_cache.end()) { /* re-validate iter */ - delete iter->second; - dns_cache.erase(iter); - } - } - - /* The hints indicate what sort of DNS results we are interested in. - * To change this to support IPv6, one change we need to make here is - * to change AF_INET to AF_UNSPEC. Everything else should just work fine. + } + if (exists) { + /* there is a cached entry, but it has expired, + * delete and free it, and fall through to a new lookup. + * We must use a unique lock here as we modify the cache. */ - memset(&hints, 0, sizeof(addrinfo)); - hints.ai_family = AF_INET; // IPv6 explicitly unsupported by Discord - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - if ((error = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &addrs))) { - /** - * The -20 makes sure the error codes dont conflict with codes given in the rest of the list - * Because C libraries love to use -1 and below directly as conflicting error codes. - */ - throw dpp::connection_exception((exception_error_code)(error - 20), std::string("getaddrinfo error: ") + gai_strerror(error)); + std::unique_lock dns_cache_lock(dns_cache_mutex); + iter = dns_cache.find(hostname); + if (iter != dns_cache.end()) { /* re-validate iter */ + delete iter->second; + dns_cache.erase(iter); } + } + + /* The hints indicate what sort of DNS results we are interested in. + * To change this to support IPv6, one change we need to make here is + * to change AF_INET to AF_UNSPEC. Everything else should just work fine. + */ + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_family = AF_INET; // IPv6 explicitly unsupported by Discord + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; - /* Thread safety scope */ - { - /* Update cache, requires unique lock */ - std::unique_lock dns_cache_lock(dns_cache_mutex); - dns_cache_entry* cache_entry = new dns_cache_entry(); - - /* The sockaddr struct contains a bunch of raw pointers that we - * must copy to the cache, before freeing it with freeaddrinfo(). - * Icky icky C APIs. - */ - memcpy(&cache_entry->addr, addrs, sizeof(addrinfo)); - memcpy(&cache_entry->ai_addr, addrs->ai_addr, addrs->ai_addrlen); - cache_entry->expire_timestamp = now + one_hour; - dns_cache[hostname] = cache_entry; - - /* Now we're done with this horrible struct, free it and return */ - freeaddrinfo(addrs); - return cache_entry; + if ((error = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &addrs))) { + /** + * The -20 makes sure the error codes dont conflict with codes given in the rest of the list + * Because C libraries love to use -1 and below directly as conflicting error codes. + */ + throw dpp::connection_exception((exception_error_code)(error - 20), std::string("getaddrinfo error: ") + gai_strerror(error)); + } + + /* Thread safety scope */ + { + /* Update cache, requires unique lock */ + std::unique_lock dns_cache_lock(dns_cache_mutex); + dns_cache_entry* cache_entry = new dns_cache_entry(); + + for (struct addrinfo* rp = addrs; rp != nullptr; rp = rp->ai_next) { + /* Discord only support ipv4, so iterate over any ipv6 results */ + if (rp->ai_family != AF_INET) { + continue; + } + /* Save address family and other metadata for later */ + memcpy(&cache_entry->addr, rp, sizeof(addrinfo)); + char buffer[128]; + sockaddr_in in{}; + std::memcpy(&in, rp->ai_addr, sizeof(sockaddr_in)); + if (inet_ntop(rp->ai_family, &in.sin_addr, buffer, sizeof(buffer))) { + cache_entry->resolved_addr = buffer; + } + break; } + + cache_entry->expire_timestamp = now + one_hour; + dns_cache[hostname] = cache_entry; + + /* Now we're done with this horrible struct, free it and return */ + freeaddrinfo(addrs); + return cache_entry; } -} // namespace dpp +} + +} diff --git a/src/dpp/socket.cpp b/src/dpp/socket.cpp new file mode 100644 index 0000000000..9313405b75 --- /dev/null +++ b/src/dpp/socket.cpp @@ -0,0 +1,63 @@ +/************************************************************************************ + * + * D++, A Lightweight C++ library for Discord + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2021 Craig Edwards and D++ contributors + * (https://github.com/brainboxdotcc/DPP/graphs/contributors) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************************/ + +#include +#include +#include + +namespace dpp { + +address_t::address_t(const std::string_view ip, uint16_t port) { + sockaddr_in address{}; + address.sin_family = AF_INET; + address.sin_port = htons(port); + address.sin_addr.s_addr = inet_addr(ip.data()); + std::memcpy(&socket_addr, &address, sizeof(address)); +} + +sockaddr* address_t::get_socket_address() { + return &socket_addr; +} + +size_t address_t::size() { + return sizeof(sockaddr_in); +} + +uint16_t address_t::get_port(socket fd) { + socklen_t len = size(); + if (getsockname(fd, &socket_addr, &len) > -1) { + sockaddr_in sin{}; + std::memcpy(&sin, &socket_addr, sizeof(sockaddr_in)); + return ntohs(sin.sin_port); + } + return 0; +} + +raii_socket::raii_socket() : fd(::socket(AF_INET, SOCK_DGRAM, 0)) { +} + +raii_socket::~raii_socket() { + close_socket(fd); +} + + +} \ No newline at end of file diff --git a/src/dpp/sslclient.cpp b/src/dpp/sslclient.cpp index d1f15ac20a..54698eb0e4 100644 --- a/src/dpp/sslclient.cpp +++ b/src/dpp/sslclient.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include /* Maximum allowed time in milliseconds for socket read/write timeouts and connect() */ @@ -318,10 +319,11 @@ void ssl_client::connect() /* Resolve hostname to IP */ int err = 0; const dns_cache_entry* addr = resolve_hostname(hostname, port); - sfd = ::socket(addr->addr.ai_family, addr->addr.ai_socktype, addr->addr.ai_protocol); + sfd = addr->make_connecting_socket(); + address_t destination = addr->get_connecting_address(from_string(this->port, std::dec)); if (sfd == ERROR_STATUS) { err = errno; - } else if (connect_with_timeout(sfd, (sockaddr*)&addr->ai_addr, (int)addr->addr.ai_addrlen, SOCKET_OP_TIMEOUT) != 0) { + } else if (connect_with_timeout(sfd, destination.get_socket_address(), destination.size(), SOCKET_OP_TIMEOUT) != 0) { close_socket(sfd); sfd = ERROR_STATUS; } diff --git a/src/dpp/voice/enabled/discover_ip.cpp b/src/dpp/voice/enabled/discover_ip.cpp index ea4f310308..341be4a80e 100644 --- a/src/dpp/voice/enabled/discover_ip.cpp +++ b/src/dpp/voice/enabled/discover_ip.cpp @@ -132,20 +132,6 @@ struct ip_discovery_packet { } }; -/** - * @brief Allocates a dpp::socket, closing it on destruction - */ -struct raii_socket { - dpp::socket fd; - - raii_socket() : fd(::socket(AF_INET, SOCK_DGRAM, 0)) { }; - raii_socket(raii_socket&) = delete; - raii_socket(raii_socket&&) = delete; - raii_socket operator=(raii_socket&) = delete; - raii_socket operator=(raii_socket&&) = delete; - ~raii_socket() { close_socket(fd); }; -}; - constexpr int discovery_timeout = 1000; std::string discord_voice_client::discover_ip() { @@ -158,19 +144,13 @@ std::string discord_voice_client::discover_ip() { ip_discovery_packet discovery(this->ssrc); if (socket.fd >= 0) { - sockaddr_in servaddr{}; - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(0); - if (bind(socket.fd, reinterpret_cast(&servaddr), sizeof(servaddr)) < 0) { + address_t bind_any; + if (bind(socket.fd, bind_any.get_socket_address(), bind_any.size()) < 0) { log(ll_warning, "Could not bind socket for IP discovery"); return ""; } - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(this->port); - servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); - if (::connect(socket.fd, reinterpret_cast(&servaddr), sizeof(sockaddr_in)) < 0) { + address_t bind_port(this->ip, this->port); + if (::connect(socket.fd, bind_port.get_socket_address(), bind_port.size()) < 0) { log(ll_warning, "Could not connect socket for IP discovery"); return ""; } diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp index 7b85cb7820..07423d3377 100644 --- a/src/dpp/voice/enabled/handle_frame.cpp +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -437,6 +437,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod this->ip = d["ip"].get(); this->port = d["port"].get(); this->ssrc = d["ssrc"].get(); + destination = address_t(this->ip, this->port); + // Modes for (auto & m : d["modes"]) { this->modes.push_back(m.get()); @@ -446,13 +448,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod dpp::socket newfd = 0; if ((newfd = ::socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { - sockaddr_in servaddr{}; - memset(&servaddr, 0, sizeof(sockaddr_in)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(0); - - if (bind(newfd, reinterpret_cast(&servaddr), sizeof(servaddr)) < 0) { + address_t bind_any; + if (bind(newfd, bind_any.get_socket_address(), bind_any.size()) < 0) { throw dpp::connection_exception(err_bind_failure, "Can't bind() client UDP socket"); } @@ -467,13 +464,7 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod this->custom_writeable_ready = [this] { write_ready(); }; this->custom_readable_ready = [this] { read_ready(); }; - int bound_port = 0; - sockaddr_in sin{}; - socklen_t len = sizeof(sin); - if (getsockname(this->fd, reinterpret_cast(&sin), &len) > -1) { - bound_port = ntohs(sin.sin_port); - } - + int bound_port = address_t().get_port(this->fd); this->write(json({ { "op", voice_opcode_connection_select_protocol }, { "d", { diff --git a/src/dpp/voice/enabled/read_write.cpp b/src/dpp/voice/enabled/read_write.cpp index 1702e6cf13..c24200b49b 100644 --- a/src/dpp/voice/enabled/read_write.cpp +++ b/src/dpp/voice/enabled/read_write.cpp @@ -43,26 +43,23 @@ dpp::socket discord_voice_client::want_read() { void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { - std::lock_guard lock(this->stream_mutex); voice_out_packet frame; - frame.packet = std::string(packet, len); + frame.packet.assign(packet, packet + len); frame.duration = duration; - outbuf.emplace_back(frame); + { + std::lock_guard lock(this->stream_mutex); + outbuf.emplace_back(frame); + } } int discord_voice_client::udp_send(const char* data, size_t length) { - sockaddr_in servaddr{}; - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(this->port); - servaddr.sin_addr.s_addr = inet_addr(this->ip.c_str()); return static_cast(sendto( this->fd, data, static_cast(length), 0, - reinterpret_cast(&servaddr), - static_cast(sizeof(sockaddr_in)) + destination.get_socket_address(), + destination.size() )); } From 5c6dcec28dc74ee544b3be552c0253cd368b743b Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 16 Oct 2024 15:30:22 +0100 Subject: [PATCH 76/99] =?UTF-8?q?refactor:=20libdave=20camel=20massacre=20?= =?UTF-8?q?=F0=9F=90=AA=F0=9F=94=AA=20(#1285)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dpp/dave/array_view.h | 25 +- src/dpp/dave/cipher_interface.cpp | 4 +- src/dpp/dave/cipher_interface.h | 28 +- src/dpp/dave/codec_utils.cpp | 275 +++++++------ src/dpp/dave/cryptor_manager.cpp | 115 +++--- src/dpp/dave/cryptor_manager.h | 26 +- src/dpp/dave/decryptor.cpp | 164 ++++---- src/dpp/dave/decryptor.h | 61 ++- src/dpp/dave/encryptor.cpp | 205 +++++----- src/dpp/dave/encryptor.h | 77 ++-- src/dpp/dave/frame_processors.cpp | 263 ++++++------- src/dpp/dave/frame_processors.h | 83 ++-- src/dpp/dave/key_ratchet.h | 3 +- src/dpp/dave/leb128.cpp | 27 +- src/dpp/dave/leb128.h | 7 +- src/dpp/dave/mls_key_ratchet.cpp | 14 +- src/dpp/dave/mls_key_ratchet.h | 8 +- src/dpp/dave/openssl_aead_cipher.cpp | 41 +- src/dpp/dave/openssl_aead_cipher.h | 34 +- src/dpp/dave/parameters.cpp | 14 +- src/dpp/dave/parameters.h | 4 +- src/dpp/dave/persisted_key_pair.cpp | 32 +- src/dpp/dave/persisted_key_pair.h | 19 +- src/dpp/dave/persisted_key_pair_generic.cpp | 62 ++- src/dpp/dave/scope_exit.h | 32 +- src/dpp/dave/session.cpp | 404 +++++++++----------- src/dpp/dave/session.h | 98 +++-- src/dpp/dave/user_credential.cpp | 17 +- src/dpp/dave/user_credential.h | 7 +- src/dpp/dave/util.cpp | 4 +- src/dpp/dave/util.h | 4 +- src/dpp/dave/version.cpp | 6 +- src/dpp/dave/version.h | 3 +- 33 files changed, 1021 insertions(+), 1145 deletions(-) diff --git a/src/dpp/dave/array_view.h b/src/dpp/dave/array_view.h index 98b6025b34..b5752e83d7 100755 --- a/src/dpp/dave/array_view.h +++ b/src/dpp/dave/array_view.h @@ -45,45 +45,50 @@ template class array_view { * @param data data pointer to array * @param size size of array */ - array_view(T* data, size_t size) - : data_(data) - , size_(size) - { + array_view(T* data, size_t size) : array(data), array_size(size) { } /** * @brief Get size of view * @return size */ - size_t size() const { return size_; } + size_t size() const { + return array_size; + } /** * @brief Get data of view from first element * @return data */ - T* data() const { return data_; } + T* data() const { + return array; + } /** * @brief Get start of view, first element * @return first element */ - T* begin() const { return data_; } + T* begin() const { + return array; + } /** * @brief Get ending iterator of view, 1+last element * @return end of view */ - T* end() const { return data_ + size_; } + T* end() const { + return array + array_size; + } private: /** * @brief array data */ - T* data_ = nullptr; + T* array = nullptr; /** * @brief Array size */ - size_t size_ = 0; + size_t array_size = 0; }; /** diff --git a/src/dpp/dave/cipher_interface.cpp b/src/dpp/dave/cipher_interface.cpp index 3dae2807cc..140debcbc3 100755 --- a/src/dpp/dave/cipher_interface.cpp +++ b/src/dpp/dave/cipher_interface.cpp @@ -28,9 +28,9 @@ namespace dpp::dave { -std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& encryptionKey) +std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& key) { - auto cipher = std::make_unique(cl, encryptionKey); + auto cipher = std::make_unique(cl, key); return cipher->is_valid() ? std::move(cipher) : nullptr; } diff --git a/src/dpp/dave/cipher_interface.h b/src/dpp/dave/cipher_interface.h index 35b849c279..ea99e0c554 100755 --- a/src/dpp/dave/cipher_interface.h +++ b/src/dpp/dave/cipher_interface.h @@ -64,25 +64,25 @@ class cipher_interface { // NOLINT /** * @brief Encrypt audio or video - * @param ciphertextBufferOut Output buffer of ciphertext - * @param plaintextBuffer Input buffer for plaintext - * @param nonceBuffer Input nonce/IV - * @param additionalData Additional data for GCM AEAD encryption - * @param tagBufferOut AEAD Tag for verification + * @param ciphertext_buffer_out Output buffer of ciphertext + * @param plaintext_buffer Input buffer for plaintext + * @param nonce_buffer Input nonce/IV + * @param additional_data Additional data for GCM AEAD encryption + * @param tag_buffer_out AEAD Tag for verification * @return true if encryption succeeded, false if it failed */ - virtual bool encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) = 0; + virtual bool encrypt(byte_view ciphertext_buffer_out, const_byte_view plaintext_buffer, const_byte_view nonce_buffer, const_byte_view additional_data, byte_view tag_buffer_out) = 0; /** * @brief Decrypt audio or video - * @param plaintextBufferOut Output buffer for plaintext - * @param ciphertextBuffer Input buffer for ciphetext - * @param tagBuffer AEAD Tag for verification - * @param nonceBuffer Nonce/IV - * @param additionalData Additional data for GCM AEAD encryption + * @param plaintext_buffer_out Output buffer for plaintext + * @param ciphertext_buffer Input buffer for ciphetext + * @param tag_buffer AEAD Tag for verification + * @param nonce_buffer Nonce/IV + * @param additional_data Additional data for GCM AEAD encryption * @return true if decryption succeeded, false if it failed */ - virtual bool decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) = 0; + virtual bool decrypt(byte_view plaintext_buffer_out, const_byte_view ciphertext_buffer, const_byte_view tag_buffer, const_byte_view nonce_buffer, const_byte_view additional_data) = 0; protected: @@ -94,10 +94,10 @@ class cipher_interface { // NOLINT /** * @brief Factory function to create new cipher interface of the best supported type for DAVE - * @param encryptionKey encryption key + * @param key encryption key * @return an instance of a class derived from cipher_interface */ -std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& encryptionKey); +std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& key); } // namespace dpp::dave diff --git a/src/dpp/dave/codec_utils.cpp b/src/dpp/dave/codec_utils.cpp index ea4269c050..85c8469412 100755 --- a/src/dpp/dave/codec_utils.cpp +++ b/src/dpp/dave/codec_utils.cpp @@ -31,98 +31,93 @@ namespace dpp::dave::codec_utils { -unencrypted_frame_header_size BytesCoveringH264PPS(const uint8_t* payload, const uint64_t sizeRemaining) +unencrypted_frame_header_size BytesCoveringH264PPS(const uint8_t* payload, const uint64_t size_remaining) { // the payload starts with three exponential golomb encoded values // (first_mb_in_slice, sps_id, pps_id) // the depacketizer needs the pps_id unencrypted // and the payload has RBSP encoding that we need to work around - constexpr uint8_t kEmulationPreventionByte = 0x03; + constexpr uint8_t emulation_prevention_byte = 0x03; - uint64_t payloadBitIndex = 0; - auto zeroBitCount = 0; - auto parsedExpGolombValues = 0; + uint64_t payload_bit_index = 0; + auto zero_bit_count = 0; + auto parsed_exp_golomb_values = 0; - while (payloadBitIndex < sizeRemaining * 8 && parsedExpGolombValues < 3) { - auto bitIndex = payloadBitIndex % 8; - auto byteIndex = payloadBitIndex / 8; - auto payloadByte = payload[byteIndex]; + while (payload_bit_index < size_remaining * 8 && parsed_exp_golomb_values < 3) { + auto bit_index = payload_bit_index % 8; + auto byte_index = payload_bit_index / 8; + auto payload_byte = payload[byte_index]; // if we're starting a new byte // check if this is an emulation prevention byte // which we skip over - if (bitIndex == 0) { - if (byteIndex >= 2 && payloadByte == kEmulationPreventionByte && - payload[byteIndex - 1] == 0 && payload[byteIndex - 2] == 0) { - payloadBitIndex += 8; + if (bit_index == 0) { + if (byte_index >= 2 && payload_byte == emulation_prevention_byte && payload[byte_index - 1] == 0 && payload[byte_index - 2] == 0) { + payload_bit_index += 8; continue; } } - if ((payloadByte & (1 << (7 - bitIndex))) == 0) { + if ((payload_byte & (1 << (7 - bit_index))) == 0) { // still in the run of leading zero bits - ++zeroBitCount; - ++payloadBitIndex; + ++zero_bit_count; + ++payload_bit_index; - if (zeroBitCount >= 32) { + if (zero_bit_count >= 32) { throw dpp::length_exception("Unexpectedly large exponential golomb encoded value"); } - } - else { + } else { // we hit a one // skip forward the number of bits dictated by the leading number of zeroes - parsedExpGolombValues += 1; - payloadBitIndex += 1 + zeroBitCount; - zeroBitCount = 0; + parsed_exp_golomb_values += 1; + payload_bit_index += 1 + zero_bit_count; + zero_bit_count = 0; } } // return the number of bytes that covers the last exp golomb encoded value - return (payloadBitIndex / 8) + 1; + return (payload_bit_index / 8) + 1; } -const uint8_t kH26XNaluLongStartCode[] = {0, 0, 0, 1}; -constexpr uint8_t kH26XNaluShortStartSequenceSize = 3; +const uint8_t nalu_long_start_code[] = {0, 0, 0, 1}; +constexpr uint8_t nalu_short_start_sequence_size = 3; -using IndexStartCodeSizePair = std::pair; +using index_start_code_size_pair = std::pair; -std::optional FindNextH26XNaluIndex(const uint8_t* buffer, const size_t bufferSize, const size_t searchStartIndex = 0) +std::optional next_h26x_nalu_index(const uint8_t* buffer, const size_t buffer_size, const size_t search_start_index = 0) { - constexpr uint8_t kH26XStartCodeHighestPossibleValue = 1; - constexpr uint8_t kH26XStartCodeEndByteValue = 1; - constexpr uint8_t kH26XStartCodeLeadingBytesValue = 0; + constexpr uint8_t start_code_highest_possible_value = 1; + constexpr uint8_t start_code_end_byte_value = 1; + constexpr uint8_t start_code_leading_bytes_value = 0; - if (bufferSize < kH26XNaluShortStartSequenceSize) { + if (buffer_size < nalu_short_start_sequence_size) { return std::nullopt; } // look for NAL unit 3 or 4 byte start code - for (size_t i = searchStartIndex; i < bufferSize - kH26XNaluShortStartSequenceSize;) { - if (buffer[i + 2] > kH26XStartCodeHighestPossibleValue) { + for (size_t i = search_start_index; i < buffer_size - nalu_short_start_sequence_size;) { + if (buffer[i + 2] > start_code_highest_possible_value) { // third byte is not 0 or 1, can't be a start code - i += kH26XNaluShortStartSequenceSize; - } - else if (buffer[i + 2] == kH26XStartCodeEndByteValue) { + i += nalu_short_start_sequence_size; + } else if (buffer[i + 2] == start_code_end_byte_value) { // third byte matches the start code end byte, might be a start code sequence - if (buffer[i + 1] == kH26XStartCodeLeadingBytesValue && - buffer[i] == kH26XStartCodeLeadingBytesValue) { + if (buffer[i + 1] == start_code_leading_bytes_value && buffer[i] == start_code_leading_bytes_value) { // confirmed start sequence {0, 0, 1} - auto nalUnitStartIndex = i + kH26XNaluShortStartSequenceSize; + auto nal_unit_start_index = i + nalu_short_start_sequence_size; - if (i >= 1 && buffer[i - 1] == kH26XStartCodeLeadingBytesValue) { + if (i >= 1 && buffer[i - 1] == start_code_leading_bytes_value) { // 4 byte start code - return std::optional({nalUnitStartIndex, 4}); + return std::optional({nal_unit_start_index, 4}); } else { // 3 byte start code - return std::optional({nalUnitStartIndex, 3}); + return std::optional({nal_unit_start_index, 3}); } } - i += kH26XNaluShortStartSequenceSize; - } - else { + i += nalu_short_start_sequence_size; + } else { // third byte is 0, might be a four byte start code ++i; } @@ -139,8 +134,8 @@ bool process_frame_opus(outbound_frame_processor& processor, array_view frame) { - constexpr uint8_t kVP8KeyFrameUnencryptedBytes = 10; - constexpr uint8_t kVP8DeltaFrameUnencryptedBytes = 1; + constexpr uint8_t key_frame_unencrypted_bytes = 10; + constexpr uint8_t delta_frame_unencrypted_bytes = 1; // parse the VP8 payload header to determine if it's a key frame // https://datatracker.ietf.org/doc/html/rfc7741#section-4.3 @@ -155,17 +150,15 @@ bool process_frame_vp8(outbound_frame_processor& processor, array_viewfirst < frame.size() - 1) { - auto [nalUnitStartIndex, startCodeSize] = *naluIndexPair; + auto nalu_index_pair = next_h26x_nalu_index(frame.data(), frame.size()); + while (nalu_index_pair && nalu_index_pair->first < frame.size() - 1) { + auto [nal_unit_start_index, start_code_size] = *nalu_index_pair; - auto nalType = frame.data()[nalUnitStartIndex] & kH264NalHeaderTypeMask; + auto nal_type = frame.data()[nal_unit_start_index] & nal_header_type_mask; // copy the start code and then the NAL unit // Because WebRTC will convert them all start codes to 4-byte on the receiver side // always write a long start code and then the NAL unit - processor.add_unencrypted_bytes(kH26XNaluLongStartCode, sizeof(kH26XNaluLongStartCode)); + processor.add_unencrypted_bytes(nalu_long_start_code, sizeof(nalu_long_start_code)); - auto nextNaluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size(), nalUnitStartIndex); - auto nextNaluStart = nextNaluIndexPair.has_value() ? nextNaluIndexPair->first - nextNaluIndexPair->second : frame.size(); + auto next_nalu_index_pair = next_h26x_nalu_index(frame.data(), frame.size(), nal_unit_start_index); + auto next_nalu_start = next_nalu_index_pair.has_value() ? next_nalu_index_pair->first - next_nalu_index_pair->second : frame.size(); - if (nalType == kH264NalTypeSlice || nalType == kH264NalTypeIdr) { + if (nal_type == nal_type_slice || nal_type == nal_type_idr) { // once we've hit a slice or an IDR // we just need to cover getting to the PPS ID - auto nalUnitPayloadStart = nalUnitStartIndex + kH264NalUnitHeaderSize; - auto nalUnitPPSBytes = BytesCoveringH264PPS(frame.data() + nalUnitPayloadStart, frame.size() - nalUnitPayloadStart); + auto nal_unit_payload_start = nal_unit_start_index + nal_unit_header_size; + auto nal_unit_pps_bytes = BytesCoveringH264PPS(frame.data() + nal_unit_payload_start, frame.size() - nal_unit_payload_start); - processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, kH264NalUnitHeaderSize + nalUnitPPSBytes); - processor.add_encrypted_bytes( - frame.data() + nalUnitStartIndex + kH264NalUnitHeaderSize + nalUnitPPSBytes, - nextNaluStart - nalUnitStartIndex - kH264NalUnitHeaderSize - nalUnitPPSBytes); - } - else { + processor.add_unencrypted_bytes(frame.data() + nal_unit_start_index, nal_unit_header_size + nal_unit_pps_bytes); + processor.add_encrypted_bytes(frame.data() + nal_unit_start_index + nal_unit_header_size + nal_unit_pps_bytes, next_nalu_start - nal_unit_start_index - nal_unit_header_size - nal_unit_pps_bytes); + } else { // copy the whole NAL unit - processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, nextNaluStart - nalUnitStartIndex); + processor.add_unencrypted_bytes(frame.data() + nal_unit_start_index, next_nalu_start - nal_unit_start_index); } - - naluIndexPair = nextNaluIndexPair; + nalu_index_pair = next_nalu_index_pair; } return true; @@ -241,43 +229,43 @@ bool process_frame_h265(outbound_frame_processor& processor, array_viewfirst < frame.size() - 1) { - auto [nalUnitStartIndex, startCodeSize] = *naluIndexPair; + auto nalu_index = next_h26x_nalu_index(frame.data(), frame.size()); + while (nalu_index && nalu_index->first < frame.size() - 1) { + auto [nal_unit_start_index, start_code_size] = *nalu_index; - uint8_t nalType = (frame.data()[nalUnitStartIndex] & kH265NalHeaderTypeMask) >> 1; + uint8_t nal_type = (frame.data()[nal_unit_start_index] & nal_header_type_mask) >> 1; // copy the start code and then the NAL unit // Because WebRTC will convert them all start codes to 4-byte on the receiver side // always write a long start code and then the NAL unit - processor.add_unencrypted_bytes(kH26XNaluLongStartCode, sizeof(kH26XNaluLongStartCode)); + processor.add_unencrypted_bytes(nalu_long_start_code, sizeof(nalu_long_start_code)); - auto nextNaluIndexPair = FindNextH26XNaluIndex(frame.data(), frame.size(), nalUnitStartIndex); - auto nextNaluStart = nextNaluIndexPair.has_value() ? nextNaluIndexPair->first - nextNaluIndexPair->second : frame.size(); + auto next_nalu_index_pair = next_h26x_nalu_index(frame.data(), frame.size(), nal_unit_start_index); + auto next_nalu_start = next_nalu_index_pair.has_value() ? next_nalu_index_pair->first - next_nalu_index_pair->second : frame.size(); - if (nalType < kH265NalTypeVclCutoff) { + if (nal_type < nal_type_vcl_cutoff) { // found a VCL NAL, encrypt the payload only - processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, kH265NalUnitHeaderSize); - processor.add_encrypted_bytes(frame.data() + nalUnitStartIndex + kH265NalUnitHeaderSize, nextNaluStart - nalUnitStartIndex - kH265NalUnitHeaderSize); + processor.add_unencrypted_bytes(frame.data() + nal_unit_start_index, nal_unit_header_size); + processor.add_encrypted_bytes(frame.data() + nal_unit_start_index + nal_unit_header_size, next_nalu_start - nal_unit_start_index - nal_unit_header_size); } else { // copy the whole NAL unit - processor.add_unencrypted_bytes(frame.data() + nalUnitStartIndex, nextNaluStart - nalUnitStartIndex); + processor.add_unencrypted_bytes(frame.data() + nal_unit_start_index, next_nalu_start - nal_unit_start_index); } - naluIndexPair = nextNaluIndexPair; + nalu_index = next_nalu_index_pair; } return true; @@ -285,28 +273,28 @@ bool process_frame_h265(outbound_frame_processor& processor, array_view frame) { - constexpr uint8_t kAv1ObuHeaderHasExtensionMask = 0b0'0000'100; - constexpr uint8_t kAv1ObuHeaderHasSizeMask = 0b0'0000'010; - constexpr uint8_t kAv1ObuHeaderTypeMask = 0b0'1111'000; - constexpr uint8_t kObuTypeTemporalDelimiter = 2; - constexpr uint8_t kObuTypeTileList = 8; - constexpr uint8_t kObuTypePadding = 15; - constexpr uint8_t kObuExtensionSizeBytes = 1; + constexpr uint8_t obu_header_has_extension_mask = 0b0'0000'100; + constexpr uint8_t obu_header_has_size_mask = 0b0'0000'010; + constexpr uint8_t obu_header_type_mask = 0b0'1111'000; + constexpr uint8_t obu_type_temporal_delimiter = 2; + constexpr uint8_t obu_type_tile_list = 8; + constexpr uint8_t obu_type_padding = 15; + constexpr uint8_t obu_extension_size_bytes = 1; size_t i = 0; while (i < frame.size()) { // Read the OBU header. - size_t obuHeaderIndex = i; - uint8_t obuHeader = frame.data()[obuHeaderIndex]; - i += sizeof(obuHeader); + size_t obu_header_index = i; + uint8_t obu_header = frame.data()[obu_header_index]; + i += sizeof(obu_header); - bool obuHasExtension = obuHeader & kAv1ObuHeaderHasExtensionMask; - bool obuHasSize = obuHeader & kAv1ObuHeaderHasSizeMask; - int obuType = (obuHeader & kAv1ObuHeaderTypeMask) >> 3; + bool obu_has_extension = obu_header & obu_header_has_extension_mask; + bool obu_has_size = obu_header & obu_header_has_size_mask; + int obu_type = (obu_header & obu_header_type_mask) >> 3; - if (obuHasExtension) { + if (obu_has_extension) { // Skip extension byte - i += kObuExtensionSizeBytes; + i += obu_extension_size_bytes; } if (i >= frame.size()) { @@ -314,12 +302,12 @@ bool process_frame_av1(outbound_frame_processor& processor, array_view frame.size()) { + if (i + obu_payload_size > frame.size()) { // Malformed frame throw dpp::logic_exception("Malformed AV1 frame: payload overflows frame"); } - i += obuPayloadSize; + i += obu_payload_size; // We only copy the OBUs that will not get dropped by the packetizer - if (obuType != kObuTypeTemporalDelimiter && obuType != kObuTypeTileList && - obuType != kObuTypePadding) { + if (obu_type != obu_type_temporal_delimiter && obu_type != obu_type_tile_list && obu_type != obu_type_padding) { // if this is the last OBU, we may need to flip the "has size" bit // which allows us to append necessary protocol data to the frame - bool rewrittenWithoutSize = false; + bool rewritten_without_size = false; - if (i == frame.size() && obuHasSize) { + if (i == frame.size() && obu_has_size) { // Flip the "has size" bit - obuHeader &= ~kAv1ObuHeaderHasSizeMask; - rewrittenWithoutSize = true; + obu_header &= ~obu_header_has_size_mask; + rewritten_without_size = true; } // write the OBU header unencrypted - processor.add_unencrypted_bytes(&obuHeader, sizeof(obuHeader)); - if (obuHasExtension) { + processor.add_unencrypted_bytes(&obu_header, sizeof(obu_header)); + if (obu_has_extension) { // write the extension byte unencrypted - processor.add_unencrypted_bytes(frame.data() + obuHeaderIndex + sizeof(obuHeader), kObuExtensionSizeBytes); + processor.add_unencrypted_bytes(frame.data() + obu_header_index + sizeof(obu_header), obu_extension_size_bytes); } // write the OBU payload size unencrypted if it was present and we didn't rewrite // without it - if (obuHasSize && !rewrittenWithoutSize) { + if (obu_has_size && !rewritten_without_size) { // The AMD AV1 encoder may pad LEB128 encoded sizes with a zero byte which the // webrtc packetizer removes. To prevent the packetizer from changing the frame, // we sanitize the size by re-writing it ourselves uint8_t leb128Buffer[LEB128_MAX_SIZE]; - size_t additionalBytesToWrite = write_leb128(obuPayloadSize, leb128Buffer); + size_t additionalBytesToWrite = write_leb128(obu_payload_size, leb128Buffer); processor.add_unencrypted_bytes(leb128Buffer, additionalBytesToWrite); } // add the OBU payload, encrypted - processor.add_encrypted_bytes(frame.data() + obuPayloadIndex, obuPayloadSize); + processor.add_encrypted_bytes(frame.data() + obu_payload_index, obu_payload_size); } } @@ -386,42 +373,42 @@ bool validate_encrypted_frame(outbound_frame_processor& processor, array_view(generation) << RATCHET_GENERATION_SHIFT_BITS | maskedNonce; + return static_cast(generation) << RATCHET_GENERATION_SHIFT_BITS | masked_nonce; } -aead_cipher_manager::aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr keyRatchet) - : clock_(clock) - , keyRatchet_(std::move(keyRatchet)) - , ratchetCreation_(clock.now()) - , ratchetExpiry_(time_point::max()) - , creator(cl) -{ +aead_cipher_manager::aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr key_ratchet) + : current_clock(clock), current_key_ratchet(std::move(key_ratchet)), ratchet_creation(clock.now()), ratchet_expiry(time_point::max()), creator(cl) { } bool aead_cipher_manager::can_process_nonce(key_generation generation, truncated_sync_nonce nonce) const { - if (!newestProcessedNonce_) { + if (!newest_processed_nonce) { return true; } - auto bigNonce = compute_wrapped_big_nonce(generation, nonce); - return bigNonce > *newestProcessedNonce_ || - std::find(missingNonces_.rbegin(), missingNonces_.rend(), bigNonce) != missingNonces_.rend(); + auto wrapped_big_nonce = compute_wrapped_big_nonce(generation, nonce); + return wrapped_big_nonce > *newest_processed_nonce || std::find(missing_nonces.rbegin(), missing_nonces.rend(), wrapped_big_nonce) != missing_nonces.rend(); } cipher_interface* aead_cipher_manager::get_cipher(key_generation generation) { cleanup_expired_ciphers(); - if (generation < oldestGeneration_) { - creator.log(dpp::ll_trace, "Received frame with old generation: " + std::to_string(generation) + ", oldest generation: " + std::to_string(oldestGeneration_)); + if (generation < oldest_generation) { + creator.log(dpp::ll_trace, "Received frame with old generation: " + std::to_string(generation) + ", oldest generation: " + std::to_string(oldest_generation)); return nullptr; } - if (generation > newestGeneration_ + MAX_GENERATION_GAP) { - creator.log(dpp::ll_trace, "Received frame with future generation: " + std::to_string(generation) + ", newest generation: " + std::to_string(newestGeneration_)); + if (generation > newest_generation + MAX_GENERATION_GAP) { + creator.log(dpp::ll_trace, "Received frame with future generation: " + std::to_string(generation) + ", newest generation: " + std::to_string(newest_generation)); return nullptr; } - auto ratchetLifetimeSec = - std::chrono::duration_cast(clock_.now() - ratchetCreation_).count(); - auto maxLifetimeFrames = MAX_FRAMES_PER_SECOND * ratchetLifetimeSec; - auto maxLifetimeGenerations = maxLifetimeFrames >> RATCHET_GENERATION_SHIFT_BITS; - if (generation > maxLifetimeGenerations) { - creator.log(dpp::ll_debug, "Received frame with generation " + std::to_string(generation) + " beyond ratchet max lifetime generations: " + std::to_string(maxLifetimeGenerations) + ", ratchet lifetime: " + std::to_string(ratchetLifetimeSec) + "s"); + auto ratchet_lifetime_sec = + std::chrono::duration_cast(current_clock.now() - ratchet_creation).count(); + auto max_lifetime_frames = MAX_FRAMES_PER_SECOND * ratchet_lifetime_sec; + auto max_lifetime_generations = max_lifetime_frames >> RATCHET_GENERATION_SHIFT_BITS; + if (generation > max_lifetime_generations) { + creator.log(dpp::ll_debug, "Received frame with generation " + std::to_string(generation) + " beyond ratchet max lifetime generations: " + std::to_string(max_lifetime_generations) + ", ratchet lifetime: " + std::to_string(ratchet_lifetime_sec) + "s"); return nullptr; } - auto it = cryptors_.find(generation); - if (it == cryptors_.end()) { + auto it = cryptor_generations.find(generation); + if (it == cryptor_generations.end()) { // We don't have a cryptor for this generation, create one - std::tie(it, std::ignore) = cryptors_.emplace(generation, make_expiring_cipher(generation)); + std::tie(it, std::ignore) = cryptor_generations.emplace(generation, make_expiring_cipher(generation)); } // Return a non-owning pointer to the cryptor @@ -105,95 +99,94 @@ cipher_interface* aead_cipher_manager::get_cipher(key_generation generation) void aead_cipher_manager::report_cipher_success(key_generation generation, truncated_sync_nonce nonce) { - auto bigNonce = compute_wrapped_big_nonce(generation, nonce); + auto wrapped_big_nonce = compute_wrapped_big_nonce(generation, nonce); // Add any missing nonces to the queue - if (!newestProcessedNonce_) { - newestProcessedNonce_ = bigNonce; + if (!newest_processed_nonce) { + newest_processed_nonce = wrapped_big_nonce; } - else if (bigNonce > *newestProcessedNonce_) { - auto oldestMissingNonce = bigNonce > MAX_MISSING_NONCES ? bigNonce - MAX_MISSING_NONCES : 0; + else if (wrapped_big_nonce > *newest_processed_nonce) { + auto oldest_missing_nonce = wrapped_big_nonce > MAX_MISSING_NONCES ? wrapped_big_nonce - MAX_MISSING_NONCES : 0; - while (!missingNonces_.empty() && missingNonces_.front() < oldestMissingNonce) { - missingNonces_.pop_front(); + while (!missing_nonces.empty() && missing_nonces.front() < oldest_missing_nonce) { + missing_nonces.pop_front(); } // If we're missing a lot, we don't want to add everything since newestProcessedNonce_ - auto missingRangeStart = std::max(oldestMissingNonce, *newestProcessedNonce_ + 1); - for (auto i = missingRangeStart; i < bigNonce; ++i) { - missingNonces_.push_back(i); + auto missing_range_start = std::max(oldest_missing_nonce, *newest_processed_nonce + 1); + for (auto i = missing_range_start; i < wrapped_big_nonce; ++i) { + missing_nonces.push_back(i); } // Update the newest processed nonce - newestProcessedNonce_ = bigNonce; + newest_processed_nonce = wrapped_big_nonce; } else { - auto it = std::find(missingNonces_.begin(), missingNonces_.end(), bigNonce); - if (it != missingNonces_.end()) { - missingNonces_.erase(it); + auto it = std::find(missing_nonces.begin(), missing_nonces.end(), wrapped_big_nonce); + if (it != missing_nonces.end()) { + missing_nonces.erase(it); } } - if (generation <= newestGeneration_ || cryptors_.find(generation) == cryptors_.end()) { + if (generation <= newest_generation || cryptor_generations.find(generation) == cryptor_generations.end()) { return; } creator.log(dpp::ll_trace, "Reporting cryptor success, generation: " + std::to_string(generation)); - newestGeneration_ = generation; + newest_generation = generation; // Update the expiry time for all old cryptors - const auto expiryTime = clock_.now() + CIPHER_EXPIRY; - for (auto& [gen, cryptor] : cryptors_) { - if (gen < newestGeneration_) { + const auto expiry_time = current_clock.now() + CIPHER_EXPIRY; + for (auto& [gen, cryptor] : cryptor_generations) { + if (gen < newest_generation) { creator.log(dpp::ll_trace, "Updating expiry for cryptor, generation: " + std::to_string(gen)); - cryptor.expiry = std::min(cryptor.expiry, expiryTime); + cryptor.expiry = std::min(cryptor.expiry, expiry_time); } } } key_generation aead_cipher_manager::compute_wrapped_generation(key_generation generation) { - return ::dpp::dave::compute_wrapped_generation(oldestGeneration_, generation); + return ::dpp::dave::compute_wrapped_generation(oldest_generation, generation); } aead_cipher_manager::expiring_cipher aead_cipher_manager::make_expiring_cipher(key_generation generation) { // Get the new key from the ratchet - auto encryptionKey = keyRatchet_->get_key(generation); - auto expiryTime = time_point::max(); + auto key = current_key_ratchet->get_key(generation); + auto expiry_time = time_point::max(); // If we got frames out of order, we might have to create a cryptor for an old generation // In that case, create it with a non-infinite expiry time as we have already transitioned // to a newer generation - if (generation < newestGeneration_) { + if (generation < newest_generation) { creator.log(dpp::ll_debug, "Creating cryptor for old generation: " + std::to_string(generation)); - expiryTime = clock_.now() + CIPHER_EXPIRY; + expiry_time = current_clock.now() + CIPHER_EXPIRY; } else { creator.log(dpp::ll_debug, "Creating cryptor for new generation: " + std::to_string(generation)); } - return {create_cipher(creator, encryptionKey), expiryTime}; + return {create_cipher(creator, key), expiry_time}; } void aead_cipher_manager::cleanup_expired_ciphers() { - for (auto it = cryptors_.begin(); it != cryptors_.end();) { + for (auto it = cryptor_generations.begin(); it != cryptor_generations.end();) { auto& [generation, cryptor] = *it; - bool expired = cryptor.expiry < clock_.now(); + bool expired = cryptor.expiry < current_clock.now(); if (expired) { creator.log(dpp::ll_trace, "Removing expired cryptor, generation: " + std::to_string(generation)); } - it = expired ? cryptors_.erase(it) : ++it; + it = expired ? cryptor_generations.erase(it) : ++it; } - while (oldestGeneration_ < newestGeneration_ && cryptors_.find(oldestGeneration_) == cryptors_.end()) { - creator.log(dpp::ll_trace, "Deleting key for old generation: " + std::to_string(oldestGeneration_)); - keyRatchet_->delete_key(oldestGeneration_); - ++oldestGeneration_; + while (oldest_generation < newest_generation && cryptor_generations.find(oldest_generation) == cryptor_generations.end()) { + creator.log(dpp::ll_trace, "Deleting key for old generation: " + std::to_string(oldest_generation)); + current_key_ratchet->delete_key(oldest_generation); + ++oldest_generation; } } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/cryptor_manager.h b/src/dpp/dave/cryptor_manager.h index 774e87f23e..88d2454e4c 100755 --- a/src/dpp/dave/cryptor_manager.h +++ b/src/dpp/dave/cryptor_manager.h @@ -77,16 +77,16 @@ class aead_cipher_manager { * @brief Constructor * @param cl Creating cluster * @param clock chrono clock - * @param keyRatchet key ratchet for cipher + * @param key_ratchet key ratchet for cipher */ - aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr keyRatchet); + aead_cipher_manager(dpp::cluster& cl, const clock_interface& clock, std::unique_ptr key_ratchet); /** * @brief Update cipher expiry * @param expiry expiry time */ void update_expiry(time_point expiry) { - ratchetExpiry_ = expiry; + ratchet_expiry = expiry; } /** @@ -94,7 +94,7 @@ class aead_cipher_manager { * @return true if expired */ bool is_expired() const { - return clock_.now() > ratchetExpiry_; + return current_clock.now() > ratchet_expiry; } /** @@ -149,17 +149,17 @@ class aead_cipher_manager { */ void cleanup_expired_ciphers(); - const clock_interface& clock_; - std::unique_ptr keyRatchet_; - std::unordered_map cryptors_; + const clock_interface& current_clock; + std::unique_ptr current_key_ratchet; + std::unordered_map cryptor_generations; - time_point ratchetCreation_; - time_point ratchetExpiry_; - key_generation oldestGeneration_{0}; - key_generation newestGeneration_{0}; + time_point ratchet_creation; + time_point ratchet_expiry; + key_generation oldest_generation{0}; + key_generation newest_generation{0}; - std::optional newestProcessedNonce_; - std::deque missingNonces_; + std::optional newest_processed_nonce; + std::deque missing_nonces; /** * @brief DPP Cluster, used for logging diff --git a/src/dpp/dave/decryptor.cpp b/src/dpp/dave/decryptor.cpp index 54bbd721d7..847b647eca 100755 --- a/src/dpp/dave/decryptor.cpp +++ b/src/dpp/dave/decryptor.cpp @@ -34,56 +34,51 @@ using namespace std::chrono_literals; namespace dpp::dave { -constexpr auto kStatsInterval = 10s; - -void decryptor::transition_to_key_ratchet(std::unique_ptr keyRatchet, duration transitionExpiry) +void decryptor::transition_to_key_ratchet(std::unique_ptr key_ratchet, duration transition_expiry) { - if (keyRatchet) { - creator.log(dpp::ll_trace, "Transitioning to new key ratchet, expiry: " + std::to_string(transitionExpiry.count())); + if (key_ratchet) { + creator.log(dpp::ll_trace, "Transitioning to new key ratchet, expiry: " + std::to_string(transition_expiry.count())); } // Update the expiry time for all existing cryptor managers - update_cryptor_manager_expiry(transitionExpiry); + update_cryptor_manager_expiry(transition_expiry); - if (keyRatchet) { - cryptorManagers_.emplace_back(creator, clock_, std::move(keyRatchet)); + if (key_ratchet) { + cryptor_managers.emplace_back(creator, current_clock, std::move(key_ratchet)); } } -void decryptor::transition_to_passthrough_mode(bool passthroughMode, duration transitionExpiry) +void decryptor::transition_to_passthrough_mode(bool passthrough_mode, duration transition_expiry) { - if (passthroughMode) { - allowPassThroughUntil_ = time_point::max(); + if (passthrough_mode) { + allow_pass_through_until = time_point::max(); } else { // Update the pass through mode expiry - auto maxExpiry = clock_.now() + transitionExpiry; - allowPassThroughUntil_ = std::min(allowPassThroughUntil_, maxExpiry); + auto max_expiry = current_clock.now() + transition_expiry; + allow_pass_through_until = std::min(allow_pass_through_until, max_expiry); } } -size_t decryptor::decrypt(media_type mediaType, - array_view encryptedFrame, - array_view frame) +size_t decryptor::decrypt(media_type this_media_type, array_view encrypted_frame, array_view frame) { - if (mediaType != media_audio && mediaType != media_video) { - creator.log(dpp::ll_trace, "decrypt failed, invalid media type: " + std::to_string(static_cast(mediaType))); + if (this_media_type != media_audio && this_media_type != media_video) { + creator.log(dpp::ll_trace, "decrypt failed, invalid media type: " + std::to_string(static_cast(this_media_type))); return 0; } - auto start = clock_.now(); + auto start = current_clock.now(); - auto localFrame = get_or_create_frame_processor(); - scope_exit cleanup([&] { return_frame_processor(std::move(localFrame)); }); + auto local_frame = get_or_create_frame_processor(); + scope_exit cleanup([&] { return_frame_processor(std::move(local_frame)); }); // Skip decrypting for silence frames - if (mediaType == media_audio && encryptedFrame.size() == OPUS_SILENCE_PACKET.size() && - std::memcmp(encryptedFrame.data(), OPUS_SILENCE_PACKET.data(), OPUS_SILENCE_PACKET.size()) == 0) { - creator.log(dpp::ll_trace, "decrypt skipping silence of size: " + std::to_string(encryptedFrame.size())); - if (encryptedFrame.data() != frame.data()) { - std::memcpy(frame.data(), encryptedFrame.data(), encryptedFrame.size()); + if (this_media_type == media_audio && encrypted_frame.size() == OPUS_SILENCE_PACKET.size() && std::memcmp(encrypted_frame.data(), OPUS_SILENCE_PACKET.data(), OPUS_SILENCE_PACKET.size()) == 0) { + creator.log(dpp::ll_trace, "decrypt skipping silence of size: " + std::to_string(encrypted_frame.size())); + if (encrypted_frame.data() != frame.data()) { + std::memcpy(frame.data(), encrypted_frame.data(), encrypted_frame.size()); } - return encryptedFrame.size(); + return encrypted_frame.size(); } // Remove any expired cryptor manager @@ -92,81 +87,75 @@ size_t decryptor::decrypt(media_type mediaType, // Process the incoming frame // This will check whether it looks like a valid encrypted frame // and if so it will parse it into its different components - localFrame->parse_frame(encryptedFrame); + local_frame->parse_frame(encrypted_frame); // If the frame is not encrypted and we can pass it through, do it - bool canUsePassThrough = allowPassThroughUntil_ > start; - if (!localFrame->is_encrypted() && canUsePassThrough) { - if (encryptedFrame.data() != frame.data()) { - std::memcpy(frame.data(), encryptedFrame.data(), encryptedFrame.size()); + bool can_use_pass_through = allow_pass_through_until > start; + if (!local_frame->is_encrypted() && can_use_pass_through) { + if (encrypted_frame.data() != frame.data()) { + std::memcpy(frame.data(), encrypted_frame.data(), encrypted_frame.size()); } - stats_[mediaType].passthroughs++; - return encryptedFrame.size(); + stats[this_media_type].passthroughs++; + return encrypted_frame.size(); } - // If the frame is not encrypted and we can't pass it through, fail - if (!localFrame->is_encrypted()) { + // If the frame is not encrypted, and we can't pass it through, fail + if (!local_frame->is_encrypted()) { creator.log(dpp::ll_warning, "decrypt failed, frame is not encrypted and pass through is disabled"); - stats_[mediaType].decrypt_failure++; + stats[this_media_type].decrypt_failure++; return 0; } // Try and decrypt with each valid cryptor // reverse iterate to try the newest cryptors first bool success = false; - for (auto it = cryptorManagers_.rbegin(); it != cryptorManagers_.rend(); ++it) { + for (auto it = cryptor_managers.rbegin(); it != cryptor_managers.rend(); ++it) { auto& cryptorManager = *it; - success = decrypt_impl(cryptorManager, mediaType, *localFrame, frame); + success = decrypt_impl(cryptorManager, this_media_type, *local_frame, frame); if (success) { break; } } - size_t bytesWritten = 0; + size_t bytes_written = 0; if (success) { - stats_[mediaType].decrypt_success++; - bytesWritten = localFrame->reconstruct_frame(frame); + stats[this_media_type].decrypt_success++; + bytes_written = local_frame->reconstruct_frame(frame); } else { - stats_[mediaType].decrypt_failure++; - creator.log(dpp::ll_warning, "decrypt failed, no valid cryptor found, type: " + std::string(mediaType ? "video" : "audio") + - ", encrypted frame size: " + std::to_string(encryptedFrame.size()) + + stats[this_media_type].decrypt_failure++; + creator.log(dpp::ll_warning, + "decrypt failed, no valid cryptor found, type: " + std::string(this_media_type ? "video" : "audio") + + ", encrypted frame size: " + std::to_string(encrypted_frame.size()) + ", plaintext frame size: " + std::to_string(frame.size()) + - ", number of cryptor managers: " + std::to_string(cryptorManagers_.size()) + - ", pass through enabled: " + std::string(canUsePassThrough ? "yes" : "no") + ", number of cryptor managers: " + std::to_string(cryptor_managers.size()) + + ", pass through enabled: " + std::string(can_use_pass_through ? "yes" : "no") ); } - auto end = clock_.now(); - stats_[mediaType].decrypt_duration += std::chrono::duration_cast(end - start).count(); + auto end = current_clock.now(); + stats[this_media_type].decrypt_duration += std::chrono::duration_cast(end - start).count(); - return bytesWritten; + return bytes_written; } -bool decryptor::decrypt_impl(aead_cipher_manager& cipher_manager, - media_type mediaType, - inbound_frame_processor& encryptedFrame, - array_view frame) +bool decryptor::decrypt_impl(aead_cipher_manager& cipher_manager, media_type this_media_type, inbound_frame_processor& encrypted_frame, array_view frame) { - auto tag = encryptedFrame.get_tag(); - auto truncatedNonce = encryptedFrame.get_truncated_nonce(); - - auto authenticatedData = encryptedFrame.get_authenticated_data(); - auto ciphertext = encryptedFrame.get_ciphertext(); - auto plaintext = encryptedFrame.get_plaintext(); + auto tag = encrypted_frame.get_tag(); + auto truncated_nonce = encrypted_frame.get_truncated_nonce(); + auto authenticated_data = encrypted_frame.get_authenticated_data(); + auto ciphertext_buffer = encrypted_frame.get_ciphertext(); + auto plaintext = encrypted_frame.get_plaintext(); // expand the truncated nonce to the full sized one needed for decryption - auto nonceBuffer = std::array(); - memcpy(nonceBuffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, - &truncatedNonce, - AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); + auto nonce_buffer = std::array(); + memcpy(nonce_buffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, &truncated_nonce, AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); - auto nonceBufferView = make_array_view(nonceBuffer.data(), nonceBuffer.size()); + auto nonce_buffer_view = make_array_view(nonce_buffer.data(), nonce_buffer.size()); - auto generation = - cipher_manager.compute_wrapped_generation(truncatedNonce >> RATCHET_GENERATION_SHIFT_BITS); + auto generation = cipher_manager.compute_wrapped_generation(truncated_nonce >> RATCHET_GENERATION_SHIFT_BITS); - if (!cipher_manager.can_process_nonce(generation, truncatedNonce)) { + if (!cipher_manager.can_process_nonce(generation, truncated_nonce)) { creator.log(dpp::ll_trace, "decrypt failed, cannot process nonce"); return false; } @@ -180,53 +169,52 @@ bool decryptor::decrypt_impl(aead_cipher_manager& cipher_manager, } // perform the decryption - bool success = cipher->decrypt(plaintext, ciphertext, tag, nonceBufferView, authenticatedData); - stats_[mediaType].decrypt_attempts++; + bool success = cipher->decrypt(plaintext, ciphertext_buffer, tag, nonce_buffer_view, authenticated_data); + stats[this_media_type].decrypt_attempts++; if (success) { - cipher_manager.report_cipher_success(generation, truncatedNonce); + cipher_manager.report_cipher_success(generation, truncated_nonce); } return success; } -size_t decryptor::get_max_plaintext_byte_size(media_type mediaType, size_t encryptedFrameSize) +size_t decryptor::get_max_plaintext_byte_size(media_type this_media_type, size_t encrypted_frame_size) { - return encryptedFrameSize; + return encrypted_frame_size; } void decryptor::update_cryptor_manager_expiry(duration expiry) { - auto maxExpiryTime = clock_.now() + expiry; - for (auto& cryptorManager : cryptorManagers_) { - cryptorManager.update_expiry(maxExpiryTime); + auto max_expiry_time = current_clock.now() + expiry; + for (auto& cryptorManager : cryptor_managers) { + cryptorManager.update_expiry(max_expiry_time); } } void decryptor::cleanup_expired_cryptor_managers() { - while (!cryptorManagers_.empty() && cryptorManagers_.front().is_expired()) { + while (!cryptor_managers.empty() && cryptor_managers.front().is_expired()) { creator.log(dpp::ll_trace, "Removing expired cryptor manager"); - cryptorManagers_.pop_front(); + cryptor_managers.pop_front(); } } std::unique_ptr decryptor::get_or_create_frame_processor() { - std::lock_guard lock(frameProcessorsMutex_); - if (frameProcessors_.empty()) { + std::lock_guard lock(frame_processors_mutex); + if (frame_processors.empty()) { return std::make_unique(creator); } - auto frameProcessor = std::move(frameProcessors_.back()); - frameProcessors_.pop_back(); - return frameProcessor; + auto frame_processor = std::move(frame_processors.back()); + frame_processors.pop_back(); + return frame_processor; } -void decryptor::return_frame_processor(std::unique_ptr frameProcessor) +void decryptor::return_frame_processor(std::unique_ptr frame_processor) { - std::lock_guard lock(frameProcessorsMutex_); - frameProcessors_.push_back(std::move(frameProcessor)); + std::lock_guard lock(frame_processors_mutex); + frame_processors.push_back(std::move(frame_processor)); } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/decryptor.h b/src/dpp/dave/decryptor.h index 804c41c826..bdf7718ee6 100755 --- a/src/dpp/dave/decryptor.h +++ b/src/dpp/dave/decryptor.h @@ -94,50 +94,48 @@ class decryptor { * of the session. Once you have a key ratchet, you can derive the key, and decrypt that * user's audio/video. * - * @param keyRatchet Key ratchet - * @param transitionExpiry Transition expiry. Old keys last this long before being withdrawn + * @param key_ratchet Key ratchet + * @param transition_expiry Transition expiry. Old keys last this long before being withdrawn * in preference of this new one. */ - void transition_to_key_ratchet(std::unique_ptr keyRatchet, - duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + void transition_to_key_ratchet(std::unique_ptr key_ratchet, duration transition_expiry = DEFAULT_TRANSITION_EXPIRY); /** * @brief Transition to passthrough mode * * Passthrough mode occurs when a non-DAVE user connects to the VC. * - * @param passthroughMode True to enable passthrough mode - * @param transitionExpiry Expiry for the transition + * @param passthrough_mode True to enable passthrough mode + * @param transition_expiry Expiry for the transition */ - void transition_to_passthrough_mode(bool passthroughMode, - duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + void transition_to_passthrough_mode(bool passthrough_mode, duration transition_expiry = DEFAULT_TRANSITION_EXPIRY); /** * @brief Decrypt a frame * - * @param mediaType type of media, audio or video - * @param encryptedFrame encrypted frame bytes + * @param this_media_type type of media, audio or video + * @param encrypted_frame encrypted frame bytes * @param frame plaintext output * @return size of decrypted frame, or 0 if failure */ - size_t decrypt(media_type mediaType, - array_view encryptedFrame, - array_view frame); + size_t decrypt(media_type this_media_type, array_view encrypted_frame, array_view frame); /** * @brief Get maximum possible decrypted size of frame from an encrypted frame - * @param mediaType type of media - * @param encryptedFrameSize encrypted frame size + * @param this_media_type type of media + * @param encrypted_frame_size encrypted frame size * @return size of plaintext buffer required */ - size_t get_max_plaintext_byte_size(media_type mediaType, size_t encryptedFrameSize); + size_t get_max_plaintext_byte_size(media_type this_media_type, size_t encrypted_frame_size); /** * @brief Get decryption stats - * @param mediaType media type, audio or video + * @param this_media_type media type, audio or video * @return decryption stats */ - decryption_stats get_stats(media_type mediaType) const { return stats_[mediaType]; } + decryption_stats get_stats(media_type this_media_type) const { + return stats[this_media_type]; + } private: /** @@ -149,12 +147,12 @@ class decryptor { * @brief Decryption implementation * * @param cipher_manager cipher manager - * @param mediaType media time, audio or video - * @param encryptedFrame encrypted frame data + * @param this_media_type media type, audio or video + * @param encrypted_frame encrypted frame data * @param frame decrypted frame data * @return True if decryption succeeded */ - bool decrypt_impl(aead_cipher_manager& cipher_manager, media_type mediaType, inbound_frame_processor& encryptedFrame, array_view frame); + bool decrypt_impl(aead_cipher_manager& cipher_manager, media_type this_media_type, inbound_frame_processor& encrypted_frame, array_view frame); /** * @brief Update expiry for an instance of the manager @@ -175,20 +173,20 @@ class decryptor { /** * Return frame processor - * @param frameProcessor frame processor + * @param frame_processor frame processor */ - void return_frame_processor(std::unique_ptr frameProcessor); + void return_frame_processor(std::unique_ptr frame_processor); - clock clock_; - std::deque cryptorManagers_; + clock current_clock; + std::deque cryptor_managers; - std::mutex frameProcessorsMutex_; - std::vector> frameProcessors_; + std::mutex frame_processors_mutex; + std::vector> frame_processors; - time_point allowPassThroughUntil_{time_point::min()}; + time_point allow_pass_through_until{time_point::min()}; - time_point lastStatsTime_{time_point::min()}; - std::array stats_; + time_point last_stats_time{time_point::min()}; + std::array stats; /** * @brief DPP Cluster, used for logging @@ -196,5 +194,4 @@ class decryptor { dpp::cluster& creator; }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp index 879976942f..716332977b 100755 --- a/src/dpp/dave/encryptor.cpp +++ b/src/dpp/dave/encryptor.cpp @@ -39,39 +39,39 @@ using namespace std::chrono_literals; namespace dpp::dave { -void encryptor::set_key_ratchet(std::unique_ptr keyRatchet) +void encryptor::set_key_ratchet(std::unique_ptr key_ratchet) { - std::lock_guard lock(keyGenMutex_); - keyRatchet_ = std::move(keyRatchet); - cryptor_ = nullptr; - currentKeyGeneration_ = 0; - truncatedNonce_ = 0; + std::lock_guard lock(key_gen_mutex); + ratchet = std::move(key_ratchet); + cryptor = nullptr; + current_key_generation = 0; + truncated_nonce = 0; } -void encryptor::set_passthrough_mode(bool passthroughMode) +void encryptor::set_passthrough_mode(bool passthrough_mode) { - passthroughMode_ = passthroughMode; - update_current_protocol_version(passthroughMode ? 0 : max_protocol_version()); + passthrough_mode_enable = passthrough_mode; + update_current_protocol_version(passthrough_mode ? 0 : max_protocol_version()); } -encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, array_view frame, array_view encryptedFrame, size_t* bytesWritten) { - if (mediaType != media_audio && mediaType != media_video) { - creator.log(dpp::ll_warning, "encrypt failed, invalid media type: " + std::to_string(static_cast(mediaType))); +encryptor::result_code encryptor::encrypt(media_type this_media_type, uint32_t ssrc, array_view frame, array_view encrypted_frame, size_t* bytes_written) { + if (this_media_type != media_audio && this_media_type != media_video) { + creator.log(dpp::ll_warning, "encrypt failed, invalid media type: " + std::to_string(static_cast(this_media_type))); return result_code::rc_encryption_failure; } - if (passthroughMode_) { + if (passthrough_mode_enable) { // Pass frame through without encrypting - std::memcpy(encryptedFrame.data(), frame.data(), frame.size()); - *bytesWritten = frame.size(); - stats_[mediaType].passthroughs++; + std::memcpy(encrypted_frame.data(), frame.data(), frame.size()); + *bytes_written = frame.size(); + stats[this_media_type].passthroughs++; return result_code::rc_success; } { - std::lock_guard lock(keyGenMutex_); - if (!keyRatchet_) { - stats_[mediaType].encrypt_failure++; + std::lock_guard lock(key_gen_mutex); + if (!ratchet) { + stats[this_media_type].encrypt_failure++; return result_code::rc_encryption_failure; } } @@ -82,27 +82,27 @@ encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, a // write the codec identifier auto codec = codec_for_ssrc(ssrc); - auto frameProcessor = get_or_create_frame_processor(); - scope_exit cleanup([&] { return_frame_processor(std::move(frameProcessor)); }); + auto frame_processor = get_or_create_frame_processor(); + scope_exit cleanup([&] { return_frame_processor(std::move(frame_processor)); }); - frameProcessor->process_frame(frame, codec); + frame_processor->process_frame(frame, codec); - const auto& unencryptedBytes = frameProcessor->get_unencrypted_bytes(); - const auto& encryptedBytes = frameProcessor->get_encrypted_bytes(); - auto& ciphertextBytes = frameProcessor->get_ciphertext_bytes(); + const auto& unencrypted_bytes = frame_processor->get_unencrypted_bytes(); + const auto& encrypted_bytes = frame_processor->get_encrypted_bytes(); + auto& ciphertext_bytes = frame_processor->get_ciphertext_bytes(); - const auto& unencryptedRanges = frameProcessor->get_unencrypted_ranges(); - auto unencryptedRangesSize = unencrypted_ranges_size(unencryptedRanges); + const auto& unencrypted_ranges = frame_processor->get_unencrypted_ranges(); + auto ranges_size = unencrypted_ranges_size(unencrypted_ranges); - auto additionalData = make_array_view(unencryptedBytes.data(), unencryptedBytes.size()); - auto plaintextBuffer = make_array_view(encryptedBytes.data(), encryptedBytes.size()); - auto ciphertextBuffer = make_array_view(ciphertextBytes.data(), ciphertextBytes.size()); + auto additional_data = make_array_view(unencrypted_bytes.data(), unencrypted_bytes.size()); + auto plaintext_buffer = make_array_view(encrypted_bytes.data(), encrypted_bytes.size()); + auto ciphertext_buffer = make_array_view(ciphertext_bytes.data(), ciphertext_bytes.size()); - auto frameSize = encryptedBytes.size() + unencryptedBytes.size(); - auto tagBuffer = make_array_view(encryptedFrame.data() + frameSize, AES_GCM_127_TRUNCATED_TAG_BYTES); + auto frame_size = encrypted_bytes.size() + unencrypted_bytes.size(); + auto tag_buffer = make_array_view(encrypted_frame.data() + frame_size, AES_GCM_127_TRUNCATED_TAG_BYTES); - auto nonceBuffer = std::array(); - auto nonceBufferView = make_array_view(nonceBuffer.data(), nonceBuffer.size()); + auto nonce_buffer = std::array(); + auto nonce_buffer_view = make_array_view(nonce_buffer.data(), nonce_buffer.size()); constexpr auto MAX_CIPHERTEXT_VALIDATION_RETRIES = 10; @@ -117,72 +117,63 @@ encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, a // which can remove start codes from the last 1 or 2 bytes of the nonce // and the two bytes of the unencrypted header bytes for (auto attempt = 1; attempt <= MAX_CIPHERTEXT_VALIDATION_RETRIES; ++attempt) { - auto [cryptor, truncatedNonce] = get_next_cryptor_and_nonce(); + auto [curr_cryptor, truncatedNonce] = get_next_cryptor_and_nonce(); - if (!cryptor) { + if (!curr_cryptor) { result = result_code::rc_encryption_failure; break; } // write the truncated nonce to our temporary full nonce array // (since the encryption call expects a full size nonce) - std::memcpy(nonceBuffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, - &truncatedNonce, - AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); + std::memcpy(nonce_buffer.data() + AES_GCM_128_TRUNCATED_SYNC_NONCE_OFFSET, &truncatedNonce, AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES); // encrypt the plaintext, adding the unencrypted header to the tag - bool success = cryptor->encrypt( - ciphertextBuffer, plaintextBuffer, nonceBufferView, additionalData, tagBuffer); + bool success = curr_cryptor->encrypt(ciphertext_buffer, plaintext_buffer, nonce_buffer_view, additional_data, tag_buffer); - stats_[mediaType].encrypt_attempts++; - stats_[mediaType].encrypt_max_attempts = - std::max(stats_[mediaType].encrypt_max_attempts, (uint64_t)attempt); + stats[this_media_type].encrypt_attempts++; + stats[this_media_type].encrypt_max_attempts = + std::max(stats[this_media_type].encrypt_max_attempts, (uint64_t)attempt); if (!success) { result = result_code::rc_encryption_failure; break; } - auto reconstructedFrameSize = frameProcessor->reconstruct_frame(encryptedFrame); + auto reconstructed_frame_size = frame_processor->reconstruct_frame(encrypted_frame); - auto nonceSize = leb128_size(truncatedNonce); + auto size = leb128_size(truncatedNonce); - auto truncatedNonceBuffer = make_array_view(tagBuffer.end(), nonceSize); - auto unencryptedRangesBuffer = - make_array_view(truncatedNonceBuffer.end(), unencryptedRangesSize); - auto supplementalBytesBuffer = - make_array_view(unencryptedRangesBuffer.end(), sizeof(supplemental_bytes_size)); - auto markerBytesBuffer = make_array_view(supplementalBytesBuffer.end(), sizeof(magic_marker)); + auto truncated_nonce_buffer = make_array_view(tag_buffer.end(), size); + auto unencrypted_ranges_buffer = make_array_view(truncated_nonce_buffer.end(), ranges_size); + auto supplemental_bytes_buffer = make_array_view(unencrypted_ranges_buffer.end(), sizeof(supplemental_bytes_size)); + auto marker_bytes_buffer = make_array_view(supplemental_bytes_buffer.end(), sizeof(magic_marker)); // write the nonce - auto res = write_leb128(truncatedNonce, truncatedNonceBuffer.begin()); - if (res != nonceSize) { + auto res = write_leb128(truncatedNonce, truncated_nonce_buffer.begin()); + if (res != size) { result = result_code::rc_encryption_failure; break; } // write the unencrypted ranges - res = serialize_unencrypted_ranges( - unencryptedRanges, unencryptedRangesBuffer.begin(), unencryptedRangesBuffer.size()); - if (res != unencryptedRangesSize) { + res = serialize_unencrypted_ranges(unencrypted_ranges, unencrypted_ranges_buffer.begin(), unencrypted_ranges_buffer.size()); + if (res != ranges_size) { result = result_code::rc_encryption_failure; break; } // write the supplemental bytes size - supplemental_bytes_size supplementalBytes = - SUPPLEMENTAL_BYTES + nonceSize + unencryptedRangesSize; - std::memcpy(supplementalBytesBuffer.data(), &supplementalBytes, sizeof(supplemental_bytes_size)); + supplemental_bytes_size supplemental_bytes = SUPPLEMENTAL_BYTES + size + ranges_size; + std::memcpy(supplemental_bytes_buffer.data(), &supplemental_bytes, sizeof(supplemental_bytes_size)); // write the marker bytes, ends the frame - std::memcpy(markerBytesBuffer.data(), &MARKER_BYTES, sizeof(magic_marker)); + std::memcpy(marker_bytes_buffer.data(), &MARKER_BYTES, sizeof(magic_marker)); - auto encryptedFrameBytes = reconstructedFrameSize + AES_GCM_127_TRUNCATED_TAG_BYTES + - nonceSize + unencryptedRangesSize + sizeof(supplemental_bytes_size) + sizeof(magic_marker); + auto encrypted_frame_bytes = reconstructed_frame_size + AES_GCM_127_TRUNCATED_TAG_BYTES + size + ranges_size + sizeof(supplemental_bytes_size) + sizeof(magic_marker); - if (codec_utils::validate_encrypted_frame( - *frameProcessor, make_array_view(encryptedFrame.data(), encryptedFrameBytes))) { - *bytesWritten = encryptedFrameBytes; + if (codec_utils::validate_encrypted_frame(*frame_processor, make_array_view(encrypted_frame.data(), encrypted_frame_bytes))) { + *bytes_written = encrypted_frame_bytes; break; } else if (attempt >= MAX_CIPHERTEXT_VALIDATION_RETRIES) { @@ -192,47 +183,48 @@ encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, a } auto now = std::chrono::steady_clock::now(); - stats_[mediaType].encrypt_duration += - std::chrono::duration_cast(now - start).count(); + stats[this_media_type].encrypt_duration += std::chrono::duration_cast(now - start).count(); if (result == result_code::rc_success) { - stats_[mediaType].encrypt_success++; + stats[this_media_type].encrypt_success++; } else { - stats_[mediaType].encrypt_failure++; + stats[this_media_type].encrypt_failure++; } return result; } -size_t encryptor::get_max_ciphertext_byte_size(media_type mediaType, size_t frameSize) +size_t encryptor::get_max_ciphertext_byte_size(media_type this_media_type, size_t frame_size) { - return frameSize + SUPPLEMENTAL_BYTES + TRANSFORM_PADDING_BYTES; + return frame_size + SUPPLEMENTAL_BYTES + TRANSFORM_PADDING_BYTES; } -void encryptor::assign_ssrc_to_codec(uint32_t ssrc, codec codecType) +void encryptor::assign_ssrc_to_codec(uint32_t ssrc, codec codec_type) { - auto existingCodecIt = std::find_if( - ssrcCodecPairs_.begin(), ssrcCodecPairs_.end(), [ssrc](const SsrcCodecPair& pair) { - return pair.first == ssrc; - }); + auto existing_codec_it = std::find_if( + ssrc_codec_pairs.begin(), ssrc_codec_pairs.end(), [ssrc](const ssrc_codec_pair& pair) { + return pair.first == ssrc; + } + ); - if (existingCodecIt == ssrcCodecPairs_.end()) { - ssrcCodecPairs_.emplace_back(ssrc, codecType); + if (existing_codec_it == ssrc_codec_pairs.end()) { + ssrc_codec_pairs.emplace_back(ssrc, codec_type); } else { - existingCodecIt->second = codecType; + existing_codec_it->second = codec_type; } } codec encryptor::codec_for_ssrc(uint32_t ssrc) { - auto existingCodecIt = std::find_if( - ssrcCodecPairs_.begin(), ssrcCodecPairs_.end(), [ssrc](const SsrcCodecPair& pair) { - return pair.first == ssrc; - }); + auto existing_codec_it = std::find_if( + ssrc_codec_pairs.begin(), ssrc_codec_pairs.end(), [ssrc](const ssrc_codec_pair& pair) { + return pair.first == ssrc; + } + ); - if (existingCodecIt != ssrcCodecPairs_.end()) { - return existingCodecIt->second; + if (existing_codec_it != ssrc_codec_pairs.end()) { + return existing_codec_it->second; } else { return codec::cd_opus; @@ -241,51 +233,50 @@ codec encryptor::codec_for_ssrc(uint32_t ssrc) std::unique_ptr encryptor::get_or_create_frame_processor() { - std::lock_guard lock(frameProcessorsMutex_); - if (frameProcessors_.empty()) { + std::lock_guard lock(frame_processors_mutex); + if (frame_processors.empty()) { return std::make_unique(creator); } - auto frameProcessor = std::move(frameProcessors_.back()); - frameProcessors_.pop_back(); - return frameProcessor; + auto frame_processor = std::move(frame_processors.back()); + frame_processors.pop_back(); + return frame_processor; } void encryptor::return_frame_processor(std::unique_ptr frameProcessor) { - std::lock_guard lock(frameProcessorsMutex_); - frameProcessors_.push_back(std::move(frameProcessor)); + std::lock_guard lock(frame_processors_mutex); + frame_processors.push_back(std::move(frameProcessor)); } encryptor::cryptor_and_nonce encryptor::get_next_cryptor_and_nonce() { - std::lock_guard lock(keyGenMutex_); - if (!keyRatchet_) { + std::lock_guard lock(key_gen_mutex); + if (!ratchet) { return {nullptr, 0}; } - auto generation = compute_wrapped_generation(currentKeyGeneration_, ++truncatedNonce_ >> RATCHET_GENERATION_SHIFT_BITS); + auto generation = compute_wrapped_generation(current_key_generation, ++truncated_nonce >> RATCHET_GENERATION_SHIFT_BITS); - if (generation != currentKeyGeneration_ || !cryptor_) { - currentKeyGeneration_ = generation; + if (generation != current_key_generation || !cryptor) { + current_key_generation = generation; - auto encryptionKey = keyRatchet_->get_key(currentKeyGeneration_); - cryptor_ = create_cipher(creator, encryptionKey); + auto key = ratchet->get_key(current_key_generation); + cryptor = create_cipher(creator, key); } - return {cryptor_, truncatedNonce_}; + return {cryptor, truncated_nonce}; } void encryptor::update_current_protocol_version(protocol_version version) { - if (version == currentProtocolVersion_) { + if (version == current_protocol_version) { return; } - currentProtocolVersion_ = version; - if (protocolVersionChangedCallback_) { - protocolVersionChangedCallback_(); + current_protocol_version = version; + if (changed_callback) { + changed_callback(); } } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/encryptor.h b/src/dpp/dave/encryptor.h index 978238d744..d5ec5e8c23 100755 --- a/src/dpp/dave/encryptor.h +++ b/src/dpp/dave/encryptor.h @@ -98,22 +98,22 @@ class encryptor { /** * @brief Set key ratchet for encryptor, this should be the bot's ratchet. - * @param keyRatchet Bot's key ratchet + * @param key_ratchet Bot's key ratchet */ - void set_key_ratchet(std::unique_ptr keyRatchet); + void set_key_ratchet(std::unique_ptr key_ratchet); /** * @brief Set encryption to passthrough mode - * @param passthroughMode true to enable passthrough mode, false to disable + * @param passthrough_mode true to enable passthrough mode, false to disable */ - void set_passthrough_mode(bool passthroughMode); + void set_passthrough_mode(bool passthrough_mode); /** * @brief True if key ratchet assigned * @return key ratchet is assigned */ bool has_key_ratchet() const { - return keyRatchet_ != nullptr; + return ratchet != nullptr; } /** @@ -121,16 +121,16 @@ class encryptor { * @return is in passthrough mode */ bool is_passthrough_mode() const { - return passthroughMode_; + return passthrough_mode_enable; } /** * @brief Assign SSRC to codec * @note This is unused - all SSRC are assumed to be OPUS for bots at present. * @param ssrc RTP SSRC - * @param codecType Codec type + * @param codec_type Codec type */ - void assign_ssrc_to_codec(uint32_t ssrc, codec codecType); + void assign_ssrc_to_codec(uint32_t ssrc, codec codec_type); /** * @brief Get codec for RTP SSRC @@ -142,34 +142,30 @@ class encryptor { /** * @brief Encrypt plaintext opus frames - * @param mediaType media type, should always be audio + * @param this_media_type media type, should always be audio * @param ssrc RTP SSRC * @param frame Frame plaintext - * @param encryptedFrame Encrypted frame - * @param bytesWritten Number of bytes written to the encrypted buffer + * @param encrypted_frame Encrypted frame + * @param bytes_written Number of bytes written to the encrypted buffer * @return Status code for encryption */ - encryptor::result_code encrypt(media_type mediaType, - uint32_t ssrc, - array_view frame, - array_view encryptedFrame, - size_t* bytesWritten); + encryptor::result_code encrypt(media_type this_media_type, uint32_t ssrc, array_view frame, array_view encrypted_frame, size_t* bytes_written); /** * @brief Get maximum possible ciphertext size for a plaintext buffer - * @param mediaType media type, should always be audio for bots - * @param frameSize frame size of plaintext buffer + * @param this_media_type media type, should always be audio for bots + * @param frame_size frame size of plaintext buffer * @return size of ciphertext buffer to allocate */ - size_t get_max_ciphertext_byte_size(media_type mediaType, size_t frameSize); + size_t get_max_ciphertext_byte_size(media_type this_media_type, size_t frame_size); /** * @brief Get encryption stats - * @param mediaType media type + * @param this_media_type media type * @return encryption stats */ - encryption_stats get_stats(media_type mediaType) const { - return stats_[mediaType]; + encryption_stats get_stats(media_type this_media_type) const { + return stats[this_media_type]; } /** @@ -182,7 +178,7 @@ class encryptor { * @param callback Callback to set */ void set_protocol_version_changed_callback(protocol_version_changed_callback callback) { - protocolVersionChangedCallback_ = std::move(callback); + changed_callback = std::move(callback); } /** @@ -190,7 +186,7 @@ class encryptor { * @return protocol version */ protocol_version get_protocol_version() const { - return currentProtocolVersion_; + return current_protocol_version; } private: @@ -223,26 +219,26 @@ class encryptor { */ void update_current_protocol_version(protocol_version version); - std::atomic_bool passthroughMode_{false}; + std::atomic_bool passthrough_mode_enable{false}; - std::mutex keyGenMutex_; - std::unique_ptr keyRatchet_; - std::shared_ptr cryptor_; - key_generation currentKeyGeneration_{0}; - truncated_sync_nonce truncatedNonce_{0}; + std::mutex key_gen_mutex; + std::unique_ptr ratchet; + std::shared_ptr cryptor; + key_generation current_key_generation{0}; + truncated_sync_nonce truncated_nonce{0}; - std::mutex frameProcessorsMutex_; - std::vector> frameProcessors_; + std::mutex frame_processors_mutex; + std::vector> frame_processors; - using SsrcCodecPair = std::pair; - std::vector ssrcCodecPairs_; + using ssrc_codec_pair = std::pair; + std::vector ssrc_codec_pairs; - using TimePoint = std::chrono::time_point; - TimePoint lastStatsTime_{TimePoint::min()}; - std::array stats_; + using time_point = std::chrono::time_point; + time_point last_stats_time{time_point::min()}; + std::array stats; - protocol_version_changed_callback protocolVersionChangedCallback_; - protocol_version currentProtocolVersion_{max_protocol_version()}; + protocol_version_changed_callback changed_callback; + protocol_version current_protocol_version{max_protocol_version()}; /** * @brief DPP Cluster, used for logging @@ -250,5 +246,4 @@ class encryptor { dpp::cluster& creator; }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/frame_processors.cpp b/src/dpp/dave/frame_processors.cpp index 15177a877e..79ae115693 100755 --- a/src/dpp/dave/frame_processors.cpp +++ b/src/dpp/dave/frame_processors.cpp @@ -74,78 +74,74 @@ std::pair OverflowAdd(size_t a, size_t b) return {didOverflow, res}; } -uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges) +uint8_t unencrypted_ranges_size(const ranges& unencrypted_ranges) { size_t size = 0; - for (const auto& range : unencryptedRanges) { + for (const auto& range : unencrypted_ranges) { size += leb128_size(range.offset); size += leb128_size(range.size); } return static_cast(size); } -uint8_t serialize_unencrypted_ranges(const ranges& unencryptedRanges, - uint8_t* buffer, - size_t bufferSize) +uint8_t serialize_unencrypted_ranges(const ranges& unencrypted_ranges, uint8_t* buffer, size_t buffer_size) { - auto writeAt = buffer; - auto end = buffer + bufferSize; - for (const auto& range : unencryptedRanges) { - auto rangeSize = leb128_size(range.offset) + leb128_size(range.size); - if (rangeSize > static_cast(end - writeAt)) { + auto write_at = buffer; + auto end = buffer + buffer_size; + for (const auto& range : unencrypted_ranges) { + auto range_size = leb128_size(range.offset) + leb128_size(range.size); + if (range_size > static_cast(end - write_at)) { break; } - writeAt += write_leb128(range.offset, writeAt); - writeAt += write_leb128(range.size, writeAt); + write_at += write_leb128(range.offset, write_at); + write_at += write_leb128(range.size, write_at); } - return writeAt - buffer; + return write_at - buffer; } -uint8_t deserialize_unencrypted_ranges(const uint8_t*& readAt, - const size_t bufferSize, - ranges& unencryptedRanges) +uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const size_t buffer_size, ranges& unencrypted_ranges) { - auto start = readAt; - auto end = readAt + bufferSize; - while (readAt < end) { - size_t offset = read_leb128(readAt, end); - if (readAt == nullptr) { + auto start = read_at; + auto end = read_at + buffer_size; + while (read_at < end) { + size_t offset = read_leb128(read_at, end); + if (read_at == nullptr) { break; } - size_t size = read_leb128(readAt, end); - if (readAt == nullptr) { + size_t size = read_leb128(read_at, end); + if (read_at == nullptr) { break; } - unencryptedRanges.push_back({offset, size}); + unencrypted_ranges.push_back({offset, size}); } - if (readAt != end) { - unencryptedRanges.clear(); - readAt = nullptr; + if (read_at != end) { + unencrypted_ranges.clear(); + read_at = nullptr; return 0; } - return readAt - start; + return read_at - start; } -bool validate_unencrypted_ranges(const ranges& unencryptedRanges, size_t frameSize) +bool validate_unencrypted_ranges(const ranges& unencrypted_ranges, size_t frame_size) { - if (unencryptedRanges.empty()) { + if (unencrypted_ranges.empty()) { return true; } // validate that the ranges are in order and don't overlap - for (auto i = 0u; i < unencryptedRanges.size(); ++i) { - auto current = unencryptedRanges[i]; + for (auto i = 0u; i < unencrypted_ranges.size(); ++i) { + auto current = unencrypted_ranges[i]; // The current range should not overflow into the next range // or if it is the last range, the end of the frame - auto maxEnd = - i + 1 < unencryptedRanges.size() ? unencryptedRanges[i + 1].offset : frameSize; + auto max_end = + i + 1 < unencrypted_ranges.size() ? unencrypted_ranges[i + 1].offset : frame_size; - auto [didOverflow, currentEnd] = OverflowAdd(current.offset, current.size); - if (didOverflow || currentEnd > maxEnd) { + auto [did_overflow, current_end] = OverflowAdd(current.offset, current.size); + if (did_overflow || current_end > max_end) { return false; } } @@ -153,189 +149,186 @@ bool validate_unencrypted_ranges(const ranges& unencryptedRanges, size_t frameSi return true; } -size_t Reconstruct(ranges ranges, - const std::vector& rangeBytes, - const std::vector& otherBytes, - const array_view& output) +size_t do_reconstruct(ranges ranges, const std::vector& range_bytes, const std::vector& other_bytes, const array_view& output) { - size_t frameIndex = 0; - size_t rangeBytesIndex = 0; - size_t otherBytesIndex = 0; - - const auto CopyRangeBytes = [&](size_t size) { - std::memcpy(output.data() + frameIndex, rangeBytes.data() + rangeBytesIndex, size); - rangeBytesIndex += size; - frameIndex += size; + size_t frame_index = 0; + size_t range_bytes_index = 0; + size_t other_bytes_index = 0; + + const auto copy_range_bytes = [&](size_t size) { + std::memcpy(output.data() + frame_index, range_bytes.data() + range_bytes_index, size); + range_bytes_index += size; + frame_index += size; }; - const auto CopyOtherBytes = [&](size_t size) { - std::memcpy(output.data() + frameIndex, otherBytes.data() + otherBytesIndex, size); - otherBytesIndex += size; - frameIndex += size; + const auto copy_other_bytes = [&](size_t size) { + std::memcpy(output.data() + frame_index, other_bytes.data() + other_bytes_index, size); + other_bytes_index += size; + frame_index += size; }; for (const auto& range : ranges) { - if (range.offset > frameIndex) { - CopyOtherBytes(range.offset - frameIndex); + if (range.offset > frame_index) { + copy_other_bytes(range.offset - frame_index); } - CopyRangeBytes(range.size); + copy_range_bytes(range.size); } - if (otherBytesIndex < otherBytes.size()) { - CopyOtherBytes(otherBytes.size() - otherBytesIndex); + if (other_bytes_index < other_bytes.size()) { + copy_other_bytes(other_bytes.size() - other_bytes_index); } - return frameIndex; + return frame_index; } void inbound_frame_processor::clear() { - isEncrypted_ = false; - originalSize_ = 0; - truncatedNonce_ = std::numeric_limits::max(); - unencryptedRanges_.clear(); - authenticated_.clear(); - ciphertext_.clear(); - plaintext_.clear(); + encrypted = false; + original_size = 0; + truncated_nonce = std::numeric_limits::max(); + unencrypted_ranges.clear(); + authenticated.clear(); + ciphertext.clear(); + plaintext.clear(); } void inbound_frame_processor::parse_frame(array_view frame) { clear(); - constexpr auto MinSupplementalBytesSize = + constexpr auto min_supplemental_bytes_size = AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); - if (frame.size() < MinSupplementalBytesSize) { + if (frame.size() < min_supplemental_bytes_size) { creator.log(dpp::ll_warning, "Encrypted frame is too small to contain min supplemental bytes"); return; } // Check the frame ends with the magic marker - auto magicMarkerBuffer = frame.end() - sizeof(magic_marker); - if (memcmp(magicMarkerBuffer, &MARKER_BYTES, sizeof(magic_marker)) != 0) { + auto magic_marker_buffer = frame.end() - sizeof(magic_marker); + if (memcmp(magic_marker_buffer, &MARKER_BYTES, sizeof(magic_marker)) != 0) { return; } // Read the supplemental bytes size - supplemental_bytes_size supplementalBytesSize; - auto supplementalBytesSizeBuffer = magicMarkerBuffer - sizeof(supplemental_bytes_size); - memcpy(&supplementalBytesSize, supplementalBytesSizeBuffer, sizeof(supplemental_bytes_size)); + supplemental_bytes_size bytes_size; + auto bytes_size_buffer = magic_marker_buffer - sizeof(supplemental_bytes_size); + memcpy(&bytes_size, bytes_size_buffer, sizeof(supplemental_bytes_size)); // Check the frame is large enough to contain the supplemental bytes - if (frame.size() < supplementalBytesSize) { + if (frame.size() < bytes_size) { creator.log(dpp::ll_warning, "Encrypted frame is too small to contain supplemental bytes"); return; } // Check that supplemental bytes size is large enough to contain the supplemental bytes - if (supplementalBytesSize < MinSupplementalBytesSize) { + if (bytes_size < min_supplemental_bytes_size) { creator.log(dpp::ll_warning, "Supplemental bytes size is too small to contain supplemental bytes"); return; } - auto supplementalBytesBuffer = frame.end() - supplementalBytesSize; + auto supplemental_bytes_buffer = frame.end() - bytes_size; // Read the tag - tag_ = make_array_view(supplementalBytesBuffer, AES_GCM_127_TRUNCATED_TAG_BYTES); + tag = make_array_view(supplemental_bytes_buffer, AES_GCM_127_TRUNCATED_TAG_BYTES); // Read the nonce - auto nonceBuffer = supplementalBytesBuffer + AES_GCM_127_TRUNCATED_TAG_BYTES; - auto readAt = nonceBuffer; - auto end = supplementalBytesSizeBuffer; - truncatedNonce_ = read_leb128(readAt, end); - if (readAt == nullptr) { + auto nonce_buffer = supplemental_bytes_buffer + AES_GCM_127_TRUNCATED_TAG_BYTES; + auto read_at = nonce_buffer; + auto end = bytes_size_buffer; + truncated_nonce = read_leb128(read_at, end); + if (read_at == nullptr) { creator.log(dpp::ll_warning, "Failed to read truncated nonce"); return; } // Read the unencrypted ranges - auto unencryptedRangesSize = end - readAt; - deserialize_unencrypted_ranges(readAt, unencryptedRangesSize, unencryptedRanges_); - if (readAt == nullptr) { + auto ranges_size = end - read_at; + deserialize_unencrypted_ranges(read_at, ranges_size, unencrypted_ranges); + if (read_at == nullptr) { creator.log(dpp::ll_warning, "Failed to read unencrypted ranges"); return; } - if (!validate_unencrypted_ranges(unencryptedRanges_, frame.size())) { + if (!validate_unencrypted_ranges(unencrypted_ranges, frame.size())) { creator.log(dpp::ll_warning, "Invalid unencrypted ranges"); return; } // This is overly aggressive but will keep reallocations to a minimum - authenticated_.reserve(frame.size()); - ciphertext_.reserve(frame.size()); - plaintext_.reserve(frame.size()); + authenticated.reserve(frame.size()); + ciphertext.reserve(frame.size()); + plaintext.reserve(frame.size()); - originalSize_ = frame.size(); + original_size = frame.size(); // Split the frame into authenticated and ciphertext bytes - size_t frameIndex = 0; - for (const auto& range : unencryptedRanges_) { - auto encryptedBytes = range.offset - frameIndex; - if (encryptedBytes > 0) { - add_ciphertext_bytes(frame.data() + frameIndex, encryptedBytes); + size_t frame_index = 0; + for (const auto& range : unencrypted_ranges) { + auto encrypted_bytes = range.offset - frame_index; + if (encrypted_bytes > 0) { + add_ciphertext_bytes(frame.data() + frame_index, encrypted_bytes); } add_authenticated_bytes(frame.data() + range.offset, range.size); - frameIndex = range.offset + range.size; + frame_index = range.offset + range.size; } - auto actualFrameSize = frame.size() - supplementalBytesSize; - if (frameIndex < actualFrameSize) { - add_ciphertext_bytes(frame.data() + frameIndex, actualFrameSize - frameIndex); + auto actual_frame_size = frame.size() - bytes_size; + if (frame_index < actual_frame_size) { + add_ciphertext_bytes(frame.data() + frame_index, actual_frame_size - frame_index); } // Make sure the plaintext buffer is the same size as the ciphertext buffer - plaintext_.resize(ciphertext_.size()); + plaintext.resize(ciphertext.size()); // We've successfully parsed the frame // Mark the frame as encrypted - isEncrypted_ = true; + encrypted = true; } size_t inbound_frame_processor::reconstruct_frame(array_view frame) const { - if (!isEncrypted_) { + if (!encrypted) { creator.log(dpp::ll_warning, "Cannot reconstruct an invalid encrypted frame"); return 0; } - if (authenticated_.size() + plaintext_.size() > frame.size()) { + if (authenticated.size() + plaintext.size() > frame.size()) { creator.log(dpp::ll_warning, "Frame is too small to contain the decrypted frame"); return 0; } - return Reconstruct(unencryptedRanges_, authenticated_, plaintext_, frame); + return do_reconstruct(unencrypted_ranges, authenticated, plaintext, frame); } void inbound_frame_processor::add_authenticated_bytes(const uint8_t* data, size_t size) { - authenticated_.resize(authenticated_.size() + size); - memcpy(authenticated_.data() + authenticated_.size() - size, data, size); + authenticated.resize(authenticated.size() + size); + memcpy(authenticated.data() + authenticated.size() - size, data, size); } void inbound_frame_processor::add_ciphertext_bytes(const uint8_t* data, size_t size) { - ciphertext_.resize(ciphertext_.size() + size); - memcpy(ciphertext_.data() + ciphertext_.size() - size, data, size); + ciphertext.resize(ciphertext.size() + size); + memcpy(ciphertext.data() + ciphertext.size() - size, data, size); } void outbound_frame_processor::reset() { - codec_ = codec::cd_unknown; - frameIndex_ = 0; - unencryptedBytes_.clear(); - encryptedBytes_.clear(); - unencryptedRanges_.clear(); + frame_codec = codec::cd_unknown; + frame_index = 0; + unencrypted_bytes.clear(); + encrypted_bytes.clear(); + unencrypted_ranges.clear(); } void outbound_frame_processor::process_frame(array_view frame, codec codec) { reset(); - codec_ = codec; - unencryptedBytes_.reserve(frame.size()); - encryptedBytes_.reserve(frame.size()); + frame_codec = codec; + unencrypted_bytes.reserve(frame.size()); + encrypted_bytes.reserve(frame.size()); bool success = false; switch (codec) { @@ -362,49 +355,47 @@ void outbound_frame_processor::process_frame(array_view frame, co } if (!success) { - frameIndex_ = 0; - unencryptedBytes_.clear(); - encryptedBytes_.clear(); - unencryptedRanges_.clear(); + frame_index = 0; + unencrypted_bytes.clear(); + encrypted_bytes.clear(); + unencrypted_ranges.clear(); add_encrypted_bytes(frame.data(), frame.size()); } - ciphertextBytes_.resize(encryptedBytes_.size()); + ciphertext_bytes.resize(encrypted_bytes.size()); } size_t outbound_frame_processor::reconstruct_frame(array_view frame) { - if (unencryptedBytes_.size() + ciphertextBytes_.size() > frame.size()) { + if (unencrypted_bytes.size() + ciphertext_bytes.size() > frame.size()) { creator.log(dpp::ll_warning, "Frame is too small to contain the encrypted frame"); return 0; } - return Reconstruct(unencryptedRanges_, unencryptedBytes_, ciphertextBytes_, frame); + return do_reconstruct(unencrypted_ranges, unencrypted_bytes, ciphertext_bytes, frame); } void outbound_frame_processor::add_unencrypted_bytes(const uint8_t* bytes, size_t size) { - if (!unencryptedRanges_.empty() && - unencryptedRanges_.back().offset + unencryptedRanges_.back().size == frameIndex_) { + if (!unencrypted_ranges.empty() && + unencrypted_ranges.back().offset + unencrypted_ranges.back().size == frame_index) { // extend the last range - unencryptedRanges_.back().size += size; - } - else { + unencrypted_ranges.back().size += size; + } else { // add a new range (offset, size) - unencryptedRanges_.push_back({frameIndex_, size}); + unencrypted_ranges.push_back({frame_index, size}); } - unencryptedBytes_.resize(unencryptedBytes_.size() + size); - memcpy(unencryptedBytes_.data() + unencryptedBytes_.size() - size, bytes, size); - frameIndex_ += size; + unencrypted_bytes.resize(unencrypted_bytes.size() + size); + memcpy(unencrypted_bytes.data() + unencrypted_bytes.size() - size, bytes, size); + frame_index += size; } void outbound_frame_processor::add_encrypted_bytes(const uint8_t* bytes, size_t size) { - encryptedBytes_.resize(encryptedBytes_.size() + size); - memcpy(encryptedBytes_.data() + encryptedBytes_.size() - size, bytes, size); - frameIndex_ += size; + encrypted_bytes.resize(encrypted_bytes.size() + size); + memcpy(encrypted_bytes.data() + encrypted_bytes.size() - size, bytes, size); + frame_index += size; } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/frame_processors.h b/src/dpp/dave/frame_processors.h index 26e58d0b42..e7301429c3 100755 --- a/src/dpp/dave/frame_processors.h +++ b/src/dpp/dave/frame_processors.h @@ -52,36 +52,36 @@ using ranges = std::vector; /** * @brief Get total size of unencrypted ranges - * @param unencryptedRanges unencrypted ranges + * @param unencrypted_ranges unencrypted ranges * @return size */ -uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges); +uint8_t unencrypted_ranges_size(const ranges& unencrypted_ranges); /** * @brief Serialise unencrypted ranges - * @param unencryptedRanges unencrypted ranges + * @param unencrypted_ranges unencrypted ranges * @param buffer buffer to serialise to - * @param bufferSize size of buffer + * @param buffer_size size of buffer * @return size of ranges written */ -uint8_t serialize_unencrypted_ranges(const ranges& unencryptedRanges, uint8_t* buffer, size_t bufferSize); +uint8_t serialize_unencrypted_ranges(const ranges& unencrypted_ranges, uint8_t* buffer, size_t buffer_size); /** * @brief Deserialise unencrypted ranges - * @param buffer buffer to write to - * @param bufferSize buffer size - * @param unencryptedRanges unencrypted ranges to write to + * @param read_at buffer to write to + * @param buffer_size buffer size + * @param unencrypted_ranges unencrypted ranges to write to * @return size of unencrypted ranges written */ -uint8_t deserialize_unencrypted_ranges(const uint8_t*& buffer, const size_t bufferSize, ranges& unencryptedRanges); +uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const size_t buffer_size, ranges& unencrypted_ranges); /** * @brief Validate unencrypted ranges - * @param unencryptedRanges unencrypted ranges - * @param frameSize frame size + * @param unencrypted_ranges unencrypted ranges + * @param frame_size frame size * @return true if validated */ -bool validate_unencrypted_ranges(const ranges& unencryptedRanges, size_t frameSize); +bool validate_unencrypted_ranges(const ranges& unencrypted_ranges, size_t frame_size); /** * @brief Processes inbound frames from the decryptor @@ -112,7 +112,7 @@ class inbound_frame_processor { * @return is encrypted */ [[nodiscard]] bool is_encrypted() const { - return isEncrypted_; + return encrypted; } /** @@ -120,7 +120,7 @@ class inbound_frame_processor { * @return Original frame size */ [[nodiscard]] size_t size() const { - return originalSize_; + return original_size; } /** @@ -133,7 +133,7 @@ class inbound_frame_processor { * @return AEAD tag */ [[nodiscard]] array_view get_tag() const { - return tag_; + return tag; } /** @@ -141,7 +141,7 @@ class inbound_frame_processor { * @return truncated sync nonce */ [[nodiscard]] truncated_sync_nonce get_truncated_nonce() const { - return truncatedNonce_; + return truncated_nonce; } /** @@ -149,7 +149,7 @@ class inbound_frame_processor { * @return AEAD auth data */ [[nodiscard]] array_view get_authenticated_data() const { - return make_array_view(authenticated_.data(), authenticated_.size()); + return make_array_view(authenticated.data(), authenticated.size()); } /** @@ -157,14 +157,16 @@ class inbound_frame_processor { * @return Ciphertext view */ [[nodiscard]] array_view get_ciphertext() const { - return make_array_view(ciphertext_.data(), ciphertext_.size()); + return make_array_view(ciphertext.data(), ciphertext.size()); } /** * @brief Get plain text * @return Plain text view */ - [[nodiscard]] array_view get_plaintext() { return make_array_view(plaintext_); } + [[nodiscard]] array_view get_plaintext() { + return make_array_view(plaintext); + } private: /** @@ -181,14 +183,14 @@ class inbound_frame_processor { */ void add_ciphertext_bytes(const uint8_t* data, size_t size); - bool isEncrypted_{false}; - size_t originalSize_{0}; - array_view tag_; - truncated_sync_nonce truncatedNonce_; - ranges unencryptedRanges_; - std::vector authenticated_; - std::vector ciphertext_; - std::vector plaintext_; + bool encrypted{false}; + size_t original_size{0}; + array_view tag; + truncated_sync_nonce truncated_nonce; + ranges unencrypted_ranges; + std::vector authenticated; + std::vector ciphertext; + std::vector plaintext; /** * @brief DPP Cluster, used for logging @@ -215,7 +217,7 @@ class outbound_frame_processor { void process_frame(array_view frame, codec codec); /** - * @brief Reconstruct frame + * @brief do_reconstruct frame * @param frame frame data * @return size of reconstructed frame */ @@ -226,7 +228,7 @@ class outbound_frame_processor { * @return codec */ [[nodiscard]] codec get_codec() const { - return codec_; + return frame_codec; } /** @@ -234,7 +236,7 @@ class outbound_frame_processor { * @return unencrypted bytes */ [[nodiscard]] const std::vector& get_unencrypted_bytes() const { - return unencryptedBytes_; + return unencrypted_bytes; } /** @@ -242,7 +244,7 @@ class outbound_frame_processor { * @return Encrypted bytes */ [[nodiscard]] const std::vector& get_encrypted_bytes() const { - return encryptedBytes_; + return encrypted_bytes; } /** @@ -250,7 +252,7 @@ class outbound_frame_processor { * @return ciphertext bytes */ [[nodiscard]] std::vector& get_ciphertext_bytes() { - return ciphertextBytes_; + return ciphertext_bytes; } /** @@ -258,7 +260,7 @@ class outbound_frame_processor { * @return unencrypted bytes */ [[nodiscard]] const ranges& get_unencrypted_ranges() const { - return unencryptedRanges_; + return unencrypted_ranges; } /** @@ -281,12 +283,12 @@ class outbound_frame_processor { void add_encrypted_bytes(const uint8_t* bytes, size_t size); private: - codec codec_{codec::cd_unknown}; - size_t frameIndex_{0}; - std::vector unencryptedBytes_; - std::vector encryptedBytes_; - std::vector ciphertextBytes_; - ranges unencryptedRanges_; + codec frame_codec{codec::cd_unknown}; + size_t frame_index{0}; + std::vector unencrypted_bytes; + std::vector encrypted_bytes; + std::vector ciphertext_bytes; + ranges unencrypted_ranges; /** * @brief DPP Cluster, used for logging @@ -294,5 +296,4 @@ class outbound_frame_processor { dpp::cluster& creator; }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/key_ratchet.h b/src/dpp/dave/key_ratchet.h index 3847f5f757..a5ed643364 100755 --- a/src/dpp/dave/key_ratchet.h +++ b/src/dpp/dave/key_ratchet.h @@ -60,5 +60,4 @@ class key_ratchet_interface { // NOLINT virtual void delete_key(key_generation generation) noexcept = 0; }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/leb128.cpp b/src/dpp/dave/leb128.cpp index 8bbe12543f..414e2ff4b7 100755 --- a/src/dpp/dave/leb128.cpp +++ b/src/dpp/dave/leb128.cpp @@ -42,29 +42,29 @@ size_t leb128_size(uint64_t value) return size + 1; } -uint64_t read_leb128(const uint8_t*& readAt, const uint8_t* end) +uint64_t read_leb128(const uint8_t*& read_at, const uint8_t* end) { uint64_t value = 0; - int fillBits = 0; - while (readAt != end && fillBits < 64 - 7) { - uint8_t leb128Byte = *readAt; - value |= uint64_t{leb128Byte & 0x7Fu} << fillBits; - ++readAt; - fillBits += 7; - if ((leb128Byte & 0x80) == 0) { + int fill_bits = 0; + while (read_at != end && fill_bits < 64 - 7) { + uint8_t leb_128_byte = *read_at; + value |= uint64_t{leb_128_byte & 0x7Fu} << fill_bits; + ++read_at; + fill_bits += 7; + if ((leb_128_byte & 0x80) == 0) { return value; } } // Read 9 bytes and didn't find the terminator byte. Check if 10th byte // is that terminator, however to fit result into uint64_t it may carry only // single bit. - if (readAt != end && *readAt <= 1) { - value |= uint64_t{*readAt} << fillBits; - ++readAt; + if (read_at != end && *read_at <= 1) { + value |= uint64_t{*read_at} << fill_bits; + ++read_at; return value; } // Failed to find terminator leb128 byte. - readAt = nullptr; + read_at = nullptr; return 0; } @@ -81,5 +81,4 @@ size_t write_leb128(uint64_t value, uint8_t* buffer) return size; } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/leb128.h b/src/dpp/dave/leb128.h index 292df06864..29b1298416 100755 --- a/src/dpp/dave/leb128.h +++ b/src/dpp/dave/leb128.h @@ -50,11 +50,11 @@ size_t leb128_size(uint64_t value); /** * @brief Reads leb128 encoded value and advance read_at by number of bytes consumed. * Sets read_at to nullptr on error. - * @param readAt start position + * @param read_at start position * @param end end position * @return decoded value */ -uint64_t read_leb128(const uint8_t*& readAt, const uint8_t* end); +uint64_t read_leb128(const uint8_t*& read_at, const uint8_t* end); /** * @brief Encodes `value` in leb128 format. Assumes buffer has size of @@ -65,5 +65,4 @@ uint64_t read_leb128(const uint8_t*& readAt, const uint8_t* end); */ size_t write_leb128(uint64_t value, uint8_t* buffer); -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/mls_key_ratchet.cpp b/src/dpp/dave/mls_key_ratchet.cpp index 1f8b1149dc..b693210b5b 100755 --- a/src/dpp/dave/mls_key_ratchet.cpp +++ b/src/dpp/dave/mls_key_ratchet.cpp @@ -27,19 +27,17 @@ namespace dpp::dave { -mls_key_ratchet::mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes baseSecret) noexcept - : hashRatchet_(suite, std::move(baseSecret)), creator(cl) -{ +mls_key_ratchet::mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes base_secret) noexcept : ratchet(suite, std::move(base_secret)), creator(cl) { } mls_key_ratchet::~mls_key_ratchet() noexcept = default; encryption_key mls_key_ratchet::get_key(key_generation generation) noexcept { - creator.log(dpp::ll_debug, "Retrieving key for generation " + std::to_string(generation) + " from HashRatchet"); + creator.log(dpp::ll_debug, "Retrieving key for generation " + std::to_string(generation) + " from hash ratchet"); try { - auto keyAndNonce = hashRatchet_.get(generation); - return std::move(keyAndNonce.key.as_vec()); + auto key_and_nonce = ratchet.get(generation); + return std::move(key_and_nonce.key.as_vec()); } catch (const std::exception& e) { creator.log(dpp::ll_warning, "Failed to retrieve key for generation " + std::to_string(generation) + ": " + std::string(e.what())); @@ -49,8 +47,8 @@ encryption_key mls_key_ratchet::get_key(key_generation generation) noexcept void mls_key_ratchet::delete_key(key_generation generation) noexcept { - hashRatchet_.erase(generation); + ratchet.erase(generation); } -} // namespace dpp::dave +} diff --git a/src/dpp/dave/mls_key_ratchet.h b/src/dpp/dave/mls_key_ratchet.h index 0a4d053819..3f61c18a72 100755 --- a/src/dpp/dave/mls_key_ratchet.h +++ b/src/dpp/dave/mls_key_ratchet.h @@ -41,9 +41,9 @@ class mls_key_ratchet : public key_ratchet_interface { // NOLINT /** * @brief Constructor * @param suite MLS ciphersuite to use - * @param baseSecret base secret + * @param base_secret base secret */ - mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes baseSecret) noexcept; + mls_key_ratchet(dpp::cluster& cl, ::mlspp::CipherSuite suite, bytes base_secret) noexcept; /** * @brief Destructor @@ -67,7 +67,7 @@ class mls_key_ratchet : public key_ratchet_interface { // NOLINT /** * @brief MLS hash ratchet */ - ::mlspp::HashRatchet hashRatchet_; + ::mlspp::HashRatchet ratchet; /** * @brief DPP Cluster, used for logging @@ -75,5 +75,5 @@ class mls_key_ratchet : public key_ratchet_interface { // NOLINT dpp::cluster& creator; }; -} // namespace dpp::dave +} diff --git a/src/dpp/dave/openssl_aead_cipher.cpp b/src/dpp/dave/openssl_aead_cipher.cpp index fcb2cad352..175710e598 100755 --- a/src/dpp/dave/openssl_aead_cipher.cpp +++ b/src/dpp/dave/openssl_aead_cipher.cpp @@ -24,26 +24,25 @@ #include #include #include -#include #include "common.h" namespace dpp::dave { -openssl_aead_cipher::openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& encryptionKey) : +openssl_aead_cipher::openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& key) : cipher_interface(_creator), - cipherCtx_(EVP_CIPHER_CTX_new()), - key_(std::vector(encryptionKey.data(), encryptionKey.data() + encryptionKey.size())) { + ssl_context(EVP_CIPHER_CTX_new()), + aes_key(std::vector(key.data(), key.data() + key.size())) { } openssl_aead_cipher::~openssl_aead_cipher() { - EVP_CIPHER_CTX_free(cipherCtx_); + EVP_CIPHER_CTX_free(ssl_context); } -bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) { +bool openssl_aead_cipher::encrypt(byte_view ciphertext_buffer_out, const_byte_view plaintext_buffer, const_byte_view nonce_buffer, const_byte_view additional_data, byte_view tag_buffer_out) { int len{}; - if (EVP_EncryptInit_ex(cipherCtx_, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { + if (EVP_EncryptInit_ex(ssl_context, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -51,13 +50,13 @@ bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view /* * Set IV length */ - if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { + if (EVP_CIPHER_CTX_ctrl(ssl_context, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } /* Initialise key and IV */ - if (EVP_EncryptInit_ex(cipherCtx_, nullptr, nullptr, key_.data(), nonceBuffer.data()) == 0) { + if (EVP_EncryptInit_ex(ssl_context, nullptr, nullptr, aes_key.data(), nonce_buffer.data()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -66,7 +65,7 @@ bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view * Provide any AAD data. This can be called zero or more times as * required */ - if (EVP_EncryptUpdate(cipherCtx_, nullptr, &len, additionalData.data(), (int)additionalData.size()) == 0) { + if (EVP_EncryptUpdate(ssl_context, nullptr, &len, additional_data.data(), (int)additional_data.size()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -75,7 +74,7 @@ bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view * Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ - if (EVP_EncryptUpdate(cipherCtx_, ciphertextBufferOut.data(), &len, plaintextBuffer.data(), (int)plaintextBuffer.size()) == 0) { + if (EVP_EncryptUpdate(ssl_context, ciphertext_buffer_out.data(), &len, plaintext_buffer.data(), (int)plaintext_buffer.size()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -84,13 +83,13 @@ bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view * Finalise the encryption. Normally ciphertext bytes may be written at * this stage, but this does not occur in GCM mode */ - if (EVP_EncryptFinal_ex(cipherCtx_, ciphertextBufferOut.data() + len, &len) == 0) { + if (EVP_EncryptFinal_ex(ssl_context, ciphertext_buffer_out.data() + len, &len) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } /* Get the tag */ - if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_GET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, tagBufferOut.data()) == 0) { + if (EVP_CIPHER_CTX_ctrl(ssl_context, EVP_CTRL_GCM_GET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, tag_buffer_out.data()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -98,24 +97,24 @@ bool openssl_aead_cipher::encrypt(byte_view ciphertextBufferOut, const_byte_view return true; } -bool openssl_aead_cipher::decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) { +bool openssl_aead_cipher::decrypt(byte_view plaintext_buffer_out, const_byte_view ciphertext_buffer, const_byte_view tag_buffer, const_byte_view nonce_buffer, const_byte_view additional_data) { int len = 0; /* Initialise the decryption operation. */ - if (EVP_DecryptInit_ex(cipherCtx_, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { + if (EVP_DecryptInit_ex(ssl_context, EVP_aes_128_gcm(), nullptr, nullptr, nullptr) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } /* Set IV length. Not necessary if this is 12 bytes (96 bits) */ - if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { + if (EVP_CIPHER_CTX_ctrl(ssl_context, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_128_NONCE_BYTES, nullptr) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } /* Initialise key and IV */ - if (EVP_DecryptInit_ex(cipherCtx_, nullptr, nullptr, key_.data(), nonceBuffer.data()) == 0) { + if (EVP_DecryptInit_ex(ssl_context, nullptr, nullptr, aes_key.data(), nonce_buffer.data()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -124,7 +123,7 @@ bool openssl_aead_cipher::decrypt(byte_view plaintextBufferOut, const_byte_view * Provide any AAD data. This can be called zero or more times as * required */ - if (EVP_DecryptUpdate(cipherCtx_, nullptr, &len, additionalData.data(), (int)additionalData.size()) == 0) { + if (EVP_DecryptUpdate(ssl_context, nullptr, &len, additional_data.data(), (int)additional_data.size()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -133,13 +132,13 @@ bool openssl_aead_cipher::decrypt(byte_view plaintextBufferOut, const_byte_view * Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ - if (EVP_DecryptUpdate(cipherCtx_, plaintextBufferOut.data(), &len, ciphertextBuffer.data(), (int)ciphertextBuffer.size()) == 0) { + if (EVP_DecryptUpdate(ssl_context, plaintext_buffer_out.data(), &len, ciphertext_buffer.data(), (int)ciphertext_buffer.size()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ - if (EVP_CIPHER_CTX_ctrl(cipherCtx_, EVP_CTRL_GCM_SET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, (void*)tagBuffer.data()) == 0) { + if (EVP_CIPHER_CTX_ctrl(ssl_context, EVP_CTRL_GCM_SET_TAG, AES_GCM_127_TRUNCATED_TAG_BYTES, (void*)tag_buffer.data()) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } @@ -148,7 +147,7 @@ bool openssl_aead_cipher::decrypt(byte_view plaintextBufferOut, const_byte_view * Finalise the decryption. A positive return value indicates success, * anything else is a failure - the plaintext is not trustworthy. */ - if (EVP_DecryptFinal_ex(cipherCtx_, plaintextBufferOut.data() + len, &len) == 0) { + if (EVP_DecryptFinal_ex(ssl_context, plaintext_buffer_out.data() + len, &len) == 0) { creator.log(dpp::ll_warning, "SSL Error: " + std::to_string(ERR_get_error())); return false; } diff --git a/src/dpp/dave/openssl_aead_cipher.h b/src/dpp/dave/openssl_aead_cipher.h index b69ae2c322..c535eef108 100755 --- a/src/dpp/dave/openssl_aead_cipher.h +++ b/src/dpp/dave/openssl_aead_cipher.h @@ -44,9 +44,9 @@ class openssl_aead_cipher : public cipher_interface { // NOLINT /** * @brief constructor * @param _creator Creator - * @param encryptionKey encryption key + * @param key encryption key */ - openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& encryptionKey); + openssl_aead_cipher(dpp::cluster& _creator, const encryption_key& key); /** * @brief Destructor @@ -58,41 +58,41 @@ class openssl_aead_cipher : public cipher_interface { // NOLINT * @return True if valid */ [[nodiscard]] bool inline is_valid() const { - return cipherCtx_ != nullptr; + return ssl_context != nullptr; } /** * @brief Encrypt plaintext to ciphertext and authenticate it with tag/AAD - * @param ciphertextBufferOut ciphertext - * @param plaintextBuffer plaintext - * @param nonceBuffer nonce/IV - * @param additionalData additional authenticated data - * @param tagBufferOut tag + * @param ciphertext_buffer_out ciphertext + * @param plaintext_buffer plaintext + * @param nonce_buffer nonce/IV + * @param additional_data additional authenticated data + * @param tag_buffer_out tag * @return True if encryption succeeded */ - bool encrypt(byte_view ciphertextBufferOut, const_byte_view plaintextBuffer, const_byte_view nonceBuffer, const_byte_view additionalData, byte_view tagBufferOut) override; + bool encrypt(byte_view ciphertext_buffer_out, const_byte_view plaintext_buffer, const_byte_view nonce_buffer, const_byte_view additional_data, byte_view tag_buffer_out) override; /** * @brief Decrypt ciphertext to plaintext if it authenticates with tag/AAD - * @param plaintextBufferOut plaintext - * @param ciphertextBuffer ciphertext - * @param tagBuffer tag - * @param nonceBuffer nonce/IV - * @param additionalData additional authenticated data + * @param plaintext_buffer_out plaintext + * @param ciphertext_buffer ciphertext + * @param tag_buffer tag + * @param nonce_buffer nonce/IV + * @param additional_data additional authenticated data * @return True if decryption succeeded */ - bool decrypt(byte_view plaintextBufferOut, const_byte_view ciphertextBuffer, const_byte_view tagBuffer, const_byte_view nonceBuffer, const_byte_view additionalData) override; + bool decrypt(byte_view plaintext_buffer_out, const_byte_view ciphertext_buffer, const_byte_view tag_buffer, const_byte_view nonce_buffer, const_byte_view additional_data) override; private: /** * @brief Using EVP_CIPHER_CTX instead of EVP_AEAD_CTX */ - EVP_CIPHER_CTX* cipherCtx_; + EVP_CIPHER_CTX* ssl_context; /** * @brief Encryption/decryption key */ - std::vector key_; + std::vector aes_key; }; } // namespace dpp::dave diff --git a/src/dpp/dave/parameters.cpp b/src/dpp/dave/parameters.cpp index 965ba80b39..bfaa44f7c2 100755 --- a/src/dpp/dave/parameters.cpp +++ b/src/dpp/dave/parameters.cpp @@ -61,17 +61,13 @@ ::mlspp::ExtensionList leaf_node_extensions_for_protocol_version(protocol_versio return ::mlspp::ExtensionList{}; } -::mlspp::ExtensionList group_extensions_for_protocol_version( - protocol_version version, - const ::mlspp::ExternalSender& externalSender) noexcept +::mlspp::ExtensionList group_extensions_for_protocol_version(protocol_version version, const ::mlspp::ExternalSender& external_sender) noexcept { - auto extensionList = ::mlspp::ExtensionList{}; - - extensionList.add(::mlspp::ExternalSendersExtension{{ - {externalSender.signature_key, externalSender.credential}, + auto extension_list = ::mlspp::ExtensionList{}; + extension_list.add(::mlspp::ExternalSendersExtension{{ + {external_sender.signature_key, external_sender.credential}, }}); - - return extensionList; + return extension_list; } } // namespace dpp::dave::mls diff --git a/src/dpp/dave/parameters.h b/src/dpp/dave/parameters.h index a5a8d4a813..798e8fa03e 100755 --- a/src/dpp/dave/parameters.h +++ b/src/dpp/dave/parameters.h @@ -77,9 +77,9 @@ ::mlspp::ExtensionList leaf_node_extensions_for_protocol_version(protocol_versio /** * @brief Get group extensions for protocol version * @param version protocol bersion - * @param externalSender external sender + * @param external_sender external sender * @return extension list */ -::mlspp::ExtensionList group_extensions_for_protocol_version(protocol_version version, const ::mlspp::ExternalSender& externalSender) noexcept; +::mlspp::ExtensionList group_extensions_for_protocol_version(protocol_version version, const ::mlspp::ExternalSender& external_sender) noexcept; } // namespace dpp::dave::mls diff --git a/src/dpp/dave/persisted_key_pair.cpp b/src/dpp/dave/persisted_key_pair.cpp index 77ea4f415e..2ed4afc87a 100755 --- a/src/dpp/dave/persisted_key_pair.cpp +++ b/src/dpp/dave/persisted_key_pair.cpp @@ -36,11 +36,10 @@ #include #include "parameters.h" -static const std::string SelfSignatureLabel = "DiscordSelfSignature"; +static const std::string self_signature_label = "DiscordSelfSignature"; -static std::string MakeKeyID(const std::string& sessionID, ::mlspp::CipherSuite suite) -{ - return sessionID + "-" + std::to_string((uint16_t)suite.cipher_suite()) + "-" + std::to_string(dpp::dave::mls::KeyVersion); +static std::string make_key_id(const std::string& session_id, ::mlspp::CipherSuite suite) { + return session_id + "-" + std::to_string((uint16_t)suite.cipher_suite()) + "-" + std::to_string(dpp::dave::mls::KeyVersion); } static std::mutex mtx; @@ -48,11 +47,10 @@ static std::map> map; namespace dpp::dave::mls { -static std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, ::mlspp::CipherSuite suite) -{ +static std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, ::mlspp::CipherSuite suite) { std::lock_guard lk(mtx); - std::string id = MakeKeyID(sessionID, suite); + std::string id = make_key_id(session_id, suite); if (auto it = map.find(id); it != map.end()) { return it->second; @@ -70,34 +68,32 @@ static std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp: return ret; } -std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, protocol_version version) +std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, protocol_version version) { - return get_persisted_key_pair(creator, ctx, sessionID, ciphersuite_for_protocol_version(version)); + return get_persisted_key_pair(creator, ctx, session_id, ciphersuite_for_protocol_version(version)); } -KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version) -{ +KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, signature_version version) { auto suite = ciphersuite_for_signature_version(version); - auto pair = get_persisted_key_pair(creator, ctx, sessionID, suite); + auto pair = get_persisted_key_pair(creator, ctx, session_id, suite); if (!pair) { return {}; } - bytes sign_data = from_ascii(sessionID + ":") + pair->public_key.data; + bytes sign_data = from_ascii(session_id + ":") + pair->public_key.data; return { pair->public_key.data.as_vec(), - std::move(pair->sign(suite, SelfSignatureLabel, sign_data).as_vec()), + std::move(pair->sign(suite, self_signature_label, sign_data).as_vec()), }; } -bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version) -{ - std::string id = MakeKeyID(sessionID, ciphersuite_for_signature_version(version)); +bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, signature_version version) { + std::string id = make_key_id(session_id, ciphersuite_for_signature_version(version)); std::lock_guard lk(mtx); map.erase(id); return ::dpp::dave::mls::detail::delete_generic_persisted_key_pair(creator, ctx, id); } -} // namespace dpp::dave::mls +} diff --git a/src/dpp/dave/persisted_key_pair.h b/src/dpp/dave/persisted_key_pair.h index 7c13c6578b..ceb5d185b1 100755 --- a/src/dpp/dave/persisted_key_pair.h +++ b/src/dpp/dave/persisted_key_pair.h @@ -55,11 +55,11 @@ using key_pair_context_type = const char *; /** * @brief Get persisted key pair * @param ctx context (pass nullptr to generate transient key) - * @param sessionID session id (pass empty string to generate transient key) + * @param session_id session id (pass empty string to generate transient key) * @param version Protocol version * @return MLS signature private key */ -std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, protocol_version version); +std::shared_ptr<::mlspp::SignaturePrivateKey> get_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, protocol_version version); /** * @brief self signed signature and key @@ -78,20 +78,20 @@ struct KeyAndSelfSignature { /** * @brief Get persisted public key * @param ctx context (set to nullptr to get transient key) - * @param sessionID session id (set to empty string to get transient key) + * @param session_id session id (set to empty string to get transient key) * @param version protocol version * @return Key and self signature */ -KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version); +KeyAndSelfSignature get_persisted_public_key(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, signature_version version); /** * @brief Delete persisted key pair * @param ctx context - * @param sessionID session ID + * @param session_id session ID * @param version protocol version * @return true if deleted */ -bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& sessionID, signature_version version); +bool delete_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& session_id, signature_version version); /** * @brief Key version for DAVE @@ -115,9 +115,6 @@ namespace detail { * @return true if deleted */ bool delete_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id); -} // namespace dpp::dave::mls::detail - -} // namespace dpp::dave::mls - - +} +} diff --git a/src/dpp/dave/persisted_key_pair_generic.cpp b/src/dpp/dave/persisted_key_pair_generic.cpp index c0a473acc7..cf1f056fee 100755 --- a/src/dpp/dave/persisted_key_pair_generic.cpp +++ b/src/dpp/dave/persisted_key_pair_generic.cpp @@ -41,10 +41,9 @@ #include "parameters.h" #include "persisted_key_pair.h" -static const std::string_view KeyStorageDir = "Discord Key Storage"; +static const std::string_view key_storage_dir = "Discord Key Storage"; -static std::filesystem::path GetKeyStorageDirectory() -{ +static std::filesystem::path get_key_storage_directory() { std::filesystem::path dir; #if defined(__ANDROID__) @@ -56,26 +55,26 @@ static std::filesystem::path GetKeyStorageDirectory() std::getline(idFile, appId, '\0'); dir /= appId; } -#else // __ANDROID__ -#if defined(_WIN32) - if (const wchar_t* appdata = _wgetenv(L"LOCALAPPDATA")) { - dir = std::filesystem::path(appdata); - } -#else // _WIN32 - if (const char* xdg = getenv("XDG_CONFIG_HOME")) { - dir = std::filesystem::path(xdg); - } - else if (const char* home = getenv("HOME")) { - dir = std::filesystem::path(home); - dir /= ".config"; - } -#endif // !_WIN32 +#else + #if defined(_WIN32) + if (const wchar_t* appdata = _wgetenv(L"LOCALAPPDATA")) { + dir = std::filesystem::path(appdata); + } + #else + if (const char* xdg = getenv("XDG_CONFIG_HOME")) { + dir = std::filesystem::path(xdg); + } + else if (const char* home = getenv("HOME")) { + dir = std::filesystem::path(home); + dir /= ".config"; + } + #endif else { return dir; } -#endif // !__ANDROID__ +#endif - return dir / KeyStorageDir; + return dir / key_storage_dir; } namespace dpp::dave::mls::detail { @@ -84,7 +83,7 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp { ::mlspp::SignaturePrivateKey ret; std::string curstr; - std::filesystem::path dir = GetKeyStorageDirectory(); + std::filesystem::path dir = get_key_storage_directory(); if (dir.empty()) { creator.log(dpp::ll_warning, "Failed to determine key storage directory in get_persisted_key_pair"); @@ -107,9 +106,9 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp return nullptr; } - std::stringstream s; - s << ifs.rdbuf(); - curstr = s.str(); + std::stringstream s; + s << ifs.rdbuf(); + curstr = s.str(); if (!ifs) { creator.log(dpp::ll_warning, "Failed to read key in get_persisted_key_pair"); return nullptr; @@ -134,9 +133,7 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp #ifdef _WIN32 int fd = _wopen(tmpfile.c_str(), _O_WRONLY | _O_CREAT | _O_TRUNC, _S_IREAD | _S_IWRITE); #else - int fd = open(tmpfile.c_str(), - O_WRONLY | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR); + int fd = open(tmpfile.c_str(), O_WRONLY | O_CLOEXEC | O_NOFOLLOW | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); #endif if (fd < 0) { creator.log(dpp::ll_warning, "Failed to open output file in get_persisted_key_pair: " + std::to_string(errno) + " (" + tmpfile.generic_string() + ")"); @@ -144,13 +141,13 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp } #ifdef _WIN32 - int wret = _write(fd, newstr.c_str(), newstr.size()); + int written = _write(fd, newstr.c_str(), newstr.size()); _close(fd); #else - ssize_t wret = write(fd, newstr.c_str(), newstr.size()); + ssize_t written = write(fd, newstr.c_str(), newstr.size()); close(fd); #endif - if (wret < 0 || (size_t)wret != newstr.size()) { + if (written < 0 || (size_t)written != newstr.size()) { creator.log(dpp::ll_warning, "Failed to write output file in get_persisted_key_pair: " + std::to_string(errno)); return nullptr; } @@ -172,7 +169,7 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp bool delete_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_type ctx, const std::string& id) { std::error_code errc; - std::filesystem::path dir = GetKeyStorageDirectory(); + std::filesystem::path dir = get_key_storage_directory(); if (dir.empty()) { creator.log(dpp::ll_warning, "Failed to determine key storage directory in get_persisted_key_pair"); return false; @@ -182,7 +179,4 @@ bool delete_generic_persisted_key_pair(dpp::cluster& creator, key_pair_context_t return std::filesystem::remove(file, errc); } -} // namespace dpp::dave::mls::detail - - - +} diff --git a/src/dpp/dave/scope_exit.h b/src/dpp/dave/scope_exit.h index 219c51dc02..6191e2e499 100755 --- a/src/dpp/dave/scope_exit.h +++ b/src/dpp/dave/scope_exit.h @@ -40,27 +40,23 @@ class [[nodiscard]] scope_exit final { * @tparam Cleanup lambda type * @param cleanup lambda */ - template explicit scope_exit(Cleanup&& cleanup) - : cleanup_{std::forward(cleanup)} - { + template explicit scope_exit(Cleanup&& cleanup) : exit_function{std::forward(cleanup)} { } /** * @brief Move constructor * @param rhs other object */ - scope_exit(scope_exit&& rhs) : cleanup_{std::move(rhs.cleanup_)} - { - rhs.cleanup_ = nullptr; + scope_exit(scope_exit&& rhs) : exit_function{std::move(rhs.exit_function)} { + rhs.exit_function = nullptr; } /** * @brief Calls lambda */ - ~scope_exit() - { - if (cleanup_) { - cleanup_(); + ~scope_exit() { + if (exit_function) { + exit_function(); } } @@ -69,17 +65,18 @@ class [[nodiscard]] scope_exit final { * @param rhs other object * @return self */ - scope_exit& operator=(scope_exit&& rhs) - { - cleanup_ = std::move(rhs.cleanup_); - rhs.cleanup_ = nullptr; + scope_exit& operator=(scope_exit&& rhs) { + exit_function = std::move(rhs.exit_function); + rhs.exit_function = nullptr; return *this; } /** * @brief Clear the lambda so it isn't called */ - void dismiss() { cleanup_ = nullptr; } + void dismiss() { + exit_function = nullptr; + } private: /** @@ -96,8 +93,7 @@ class [[nodiscard]] scope_exit final { /** * @brief Lambda to call */ - std::function cleanup_; + std::function exit_function; }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/session.cpp b/src/dpp/dave/session.cpp index 5aa0859856..0bb7f10568 100755 --- a/src/dpp/dave/session.cpp +++ b/src/dpp/dave/session.cpp @@ -23,12 +23,10 @@ * ************************************************************************************/ #include "session.h" - #include #include #include #include - #include #include #include @@ -38,12 +36,11 @@ #include "parameters.h" #include "persisted_key_pair.h" #include "util.h" - #include "openssl/evp.h" -#define TRACK_MLS_ERROR(reason) \ - if (onMLSFailureCallback_) { \ - onMLSFailureCallback_(__FUNCTION__, reason); \ +#define TRACK_MLS_ERROR(reason) \ + if (failure_callback) { \ + failure_callback(__FUNCTION__, reason); \ } namespace dpp::dave::mls { @@ -53,24 +50,24 @@ struct queued_proposal { ::mlspp::bytes_ns::bytes ref; }; -session::session(dpp::cluster& cluster, key_pair_context_type context, const std::string& authSessionId, mls_failure_callback callback) noexcept - : signingKeyId_(authSessionId), keyPairContext_(context), onMLSFailureCallback_(std::move(callback)), creator(cluster) +session::session(dpp::cluster& cluster, key_pair_context_type context, const std::string& auth_session_id, mls_failure_callback callback) noexcept + : signing_key_id(auth_session_id), key_pair_context(context), failure_callback(std::move(callback)), creator(cluster) { creator.log(dpp::ll_debug, "Creating a new MLS session"); } session::~session() noexcept = default; -void session::init(protocol_version version, uint64_t groupId, std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept { +void session::init(protocol_version version, uint64_t group_id, std::string const& self_user_id, std::shared_ptr<::mlspp::SignaturePrivateKey>& transient_key) noexcept { reset(); - selfUserId_ = selfUserId; + bot_user_id = self_user_id; - creator.log(dpp::ll_debug, "Initializing MLS session with protocol version " + std::to_string(version) + " and group ID " + std::to_string(groupId)); - protocolVersion_ = version; - groupId_ = std::move(big_endian_bytes_from(groupId).as_vec()); + creator.log(dpp::ll_debug, "Initializing MLS session with protocol version " + std::to_string(version) + " and group ID " + std::to_string(group_id)); + session_protocol_version = version; + session_group_id = std::move(big_endian_bytes_from(group_id).as_vec()); - init_leaf_node(selfUserId, transientKey); + init_leaf_node(self_user_id, transient_key); create_pending_group(); } @@ -80,43 +77,43 @@ void session::reset() noexcept { clear_pending_state(); - currentState_.reset(); - outboundCachedGroupState_.reset(); + current_state.reset(); + outbound_cached_group_state.reset(); - protocolVersion_ = 0; - groupId_.clear(); + session_protocol_version = 0; + session_group_id.clear(); } void session::set_protocol_version(protocol_version version) noexcept { - if (version != protocolVersion_) { + if (version != session_protocol_version) { // when we need to retain backwards compatibility // there may be some changes to the MLS objects required here // until then we can just update the stored version - protocolVersion_ = version; + session_protocol_version = version; } } std::vector session::get_last_epoch_authenticator() const noexcept { - if (!currentState_) { + if (!current_state) { creator.log(dpp::ll_debug, "Cannot get epoch authenticator without an established MLS group"); return {}; } - return std::move(currentState_->epoch_authenticator().as_vec()); + return std::move(current_state->epoch_authenticator().as_vec()); } -void session::set_external_sender(const std::vector &externalSenderPackage) noexcept +void session::set_external_sender(const std::vector &external_sender_package) noexcept try { - if (currentState_) { + if (current_state) { creator.log(dpp::ll_warning, "Cannot set external sender after joining/creating an MLS group"); return; } creator.log(dpp::ll_debug, "Unmarshalling MLS external sender"); - externalSender_ = std::make_unique<::mlspp::ExternalSender>( - ::mlspp::tls::get<::mlspp::ExternalSender>(externalSenderPackage)); + mls_external_sender = std::make_unique<::mlspp::ExternalSender>( + ::mlspp::tls::get<::mlspp::ExternalSender>(external_sender_package)); - if (!groupId_.empty()) { + if (!session_group_id.empty()) { create_pending_group(); } } @@ -126,41 +123,41 @@ catch (const std::exception& e) { return; } -std::optional> session::process_proposals(std::vector proposals, std::set const& recognizedUserIDs) noexcept +std::optional> session::process_proposals(std::vector proposals, std::set const& recognised_user_ids) noexcept try { - if (!pendingGroupState_ && !currentState_) { + if (!pending_group_state && !current_state) { creator.log(dpp::ll_debug, "Cannot process proposals without any pending or established MLS group state"); return std::nullopt; } - if (!stateWithProposals_) { - stateWithProposals_ = std::make_unique<::mlspp::State>( - pendingGroupState_ ? *pendingGroupState_ : *currentState_); + if (!state_with_proposals) { + state_with_proposals = std::make_unique<::mlspp::State>( + pending_group_state ? *pending_group_state : *current_state); } creator.log(dpp::ll_debug, "Processing MLS proposals message of " + std::to_string(proposals.size()) + " bytes"); - ::mlspp::tls::istream inStream(proposals); + ::mlspp::tls::istream in_stream(proposals); - bool isRevoke = false; - inStream >> isRevoke; + bool is_revoke = false; + in_stream >> is_revoke; - if (isRevoke) { + if (is_revoke) { creator.log(dpp::ll_trace, "Revoking from proposals"); } - const auto suite = stateWithProposals_->cipher_suite(); + const auto suite = state_with_proposals->cipher_suite(); - if (isRevoke) { + if (is_revoke) { std::vector<::mlspp::bytes_ns::bytes> refs; - inStream >> refs; + in_stream >> refs; for (const auto& ref : refs) { bool found = false; - for (auto it = proposalQueue_.begin(); it != proposalQueue_.end(); it++) { + for (auto it = proposal_queue.begin(); it != proposal_queue.end(); it++) { if (it->ref == ref) { found = true; - proposalQueue_.erase(it); + proposal_queue.erase(it); break; } } @@ -172,71 +169,68 @@ try { } } - stateWithProposals_ = std::make_unique<::mlspp::State>( - pendingGroupState_ ? *pendingGroupState_ : *currentState_); + state_with_proposals = std::make_unique<::mlspp::State>( + pending_group_state ? *pending_group_state : *current_state); - for (auto& prop : proposalQueue_) { + for (auto& prop : proposal_queue) { // success will queue the proposal, failure will throw - stateWithProposals_->handle(prop.content); + state_with_proposals->handle(prop.content); } - } - else { + } else { std::vector<::mlspp::MLSMessage> messages; - inStream >> messages; + in_stream >> messages; - for (const auto& proposalMessage : messages) { - auto validatedMessage = stateWithProposals_->unwrap(proposalMessage); + for (const auto& proposal_message : messages) { + auto validated_content = state_with_proposals->unwrap(proposal_message); - if (!validate_proposal_message(validatedMessage.authenticated_content(), - *stateWithProposals_, - recognizedUserIDs)) { + if (!validate_proposal_message(validated_content.authenticated_content(), + *state_with_proposals, + recognised_user_ids)) { return std::nullopt; } // success will queue the proposal, failure will throw - stateWithProposals_->handle(validatedMessage); + state_with_proposals->handle(validated_content); - auto ref = suite.ref(validatedMessage.authenticated_content()); + auto ref = suite.ref(validated_content.authenticated_content()); - proposalQueue_.push_back({ - std::move(validatedMessage), + proposal_queue.push_back({ + std::move(validated_content), std::move(ref), }); } } // generate a commit - auto commitSecret = ::mlspp::hpke::random_bytes(suite.secret_size()); + auto commit_secret = ::mlspp::hpke::random_bytes(suite.secret_size()); - auto commitOpts = ::mlspp::CommitOpts{ - {}, // no extra proposals - true, // inline tree in welcome - false, // do not force path - {} // default leaf node options + auto commit_options = ::mlspp::CommitOpts{ + {}, // no extra proposals + true, // inline tree in welcome + false, // do not force path + {} // default leaf node options }; - auto [commitMessage, welcomeMessage, newState] = - stateWithProposals_->commit(commitSecret, commitOpts, {}); + auto [commit_message, welcome_message, new_state] = state_with_proposals->commit(commit_secret, commit_options, {}); creator.log(dpp::ll_debug, "Prepared commit/welcome/next state for MLS group from received proposals"); // combine the commit and welcome messages into a single buffer - auto outStream = ::mlspp::tls::ostream(); - outStream << commitMessage; + auto out_stream = ::mlspp::tls::ostream(); + out_stream << commit_message; // keep a copy of the commit, we can check incoming pending group commit later for a match - pendingGroupCommit_ = std::make_unique<::mlspp::MLSMessage>(std::move(commitMessage)); + pending_group_commit = std::make_unique<::mlspp::MLSMessage>(std::move(commit_message)); // if there were any add proposals in this commit, then we also include the welcome message - if (welcomeMessage.secrets.size() > 0) { - outStream << welcomeMessage; + if (welcome_message.secrets.size() > 0) { + out_stream << welcome_message; } // cache the outbound state in case we're the winning sender - outboundCachedGroupState_ = std::make_unique<::mlspp::State>(std::move(newState)); - + outbound_cached_group_state = std::make_unique<::mlspp::State>(std::move(new_state)); - return outStream.bytes(); + return out_stream.bytes(); } catch (const std::exception& e) { creator.log(dpp::ll_warning, "Failed to parse MLS proposals: " + std::string(e.what())); @@ -244,15 +238,15 @@ catch (const std::exception& e) { return std::nullopt; } -bool session::is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognizedUserIDs) const +bool session::is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognised_user_ids) const { - std::string uid = user_credential_to_string(cred, protocolVersion_); + std::string uid = user_credential_to_string(cred, session_protocol_version); if (uid.empty()) { creator.log(dpp::ll_warning, "Attempted to verify credential of unexpected type"); return false; } - if (recognizedUserIDs.find(uid) == recognizedUserIDs.end()) { + if (recognised_user_ids.find(uid) == recognised_user_ids.end()) { creator.log(dpp::ll_warning, "Attempted to verify credential for unrecognized user ID: " + uid); return false; } @@ -260,15 +254,15 @@ bool session::is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognizedUserIDs) const { +bool session::validate_proposal_message(::mlspp::AuthenticatedContent const& message, ::mlspp::State const& target_state, std::set const& recognised_user_ids) const { if (message.wire_format != ::mlspp::WireFormat::mls_public_message) { creator.log(dpp::ll_warning, "MLS proposal message must be PublicMessage"); TRACK_MLS_ERROR("Invalid proposal wire format"); return false; } - if (message.content.epoch != targetState.epoch()) { - creator.log(dpp::ll_warning, "MLS proposal message must be for current epoch (" + std::to_string(message.content.epoch) + " != " + std::to_string(targetState.epoch()) + ")"); + if (message.content.epoch != target_state.epoch()) { + creator.log(dpp::ll_warning, "MLS proposal message must be for current epoch (" + std::to_string(message.content.epoch) + " != " + std::to_string(target_state.epoch()) + ")"); TRACK_MLS_ERROR("Proposal epoch mismatch"); return false; } @@ -290,7 +284,7 @@ bool session::validate_proposal_message(::mlspp::AuthenticatedContent const& mes case ::mlspp::ProposalType::add: { const auto& credential = ::mlspp::tls::var::get<::mlspp::Add>(proposal.content).key_package.leaf_node.credential; - if (!is_recognized_user_id(credential, recognizedUserIDs)) { + if (!is_recognized_user_id(credential, recognised_user_ids)) { creator.log(dpp::ll_warning, "MLS proposal must be for recognised user"); TRACK_MLS_ERROR("Unexpected user ID in add proposal"); return false; @@ -311,11 +305,11 @@ bool session::validate_proposal_message(::mlspp::AuthenticatedContent const& mes bool session::can_process_commit(const ::mlspp::MLSMessage& commit) noexcept { - if (!stateWithProposals_) { + if (!state_with_proposals) { return false; } - if (commit.group_id() != groupId_) { + if (commit.group_id() != session_group_id) { creator.log(dpp::ll_warning, "MLS commit message was for unexpected group"); return false; } @@ -327,34 +321,32 @@ roster_variant session::process_commit(std::vector commit) noexcept try { creator.log(dpp::ll_debug, "Processing commit"); - auto commitMessage = ::mlspp::tls::get<::mlspp::MLSMessage>(commit); + auto commit_message = ::mlspp::tls::get<::mlspp::MLSMessage>(commit); - if (!can_process_commit(commitMessage)) { + if (!can_process_commit(commit_message)) { creator.log(dpp::ll_warning, "process_commit called with unprocessable MLS commit"); return ignored_t{}; } // in case we're the sender of this commit // we need to pull the cached state from our outbound cache - std::optional<::mlspp::State> optionalCachedState = std::nullopt; - if (outboundCachedGroupState_) { - optionalCachedState = *(outboundCachedGroupState_.get()); + std::optional<::mlspp::State> optional_cached_state = std::nullopt; + if (outbound_cached_group_state) { + optional_cached_state = *(outbound_cached_group_state.get()); } - auto newState = stateWithProposals_->handle(commitMessage, optionalCachedState); - - if (!newState) { + auto new_state = state_with_proposals->handle(commit_message, optional_cached_state); + if (!new_state) { creator.log(dpp::ll_warning, "MLS commit handling did not produce a new state"); return failed_t{}; } - creator.log(dpp::ll_debug, "Successfully processed MLS commit, updating state; our leaf index is " + std::to_string(newState->index().val) + "; current epoch is " + std::to_string(newState->epoch())); + creator.log(dpp::ll_debug, "Successfully processed MLS commit, updating state; our leaf index is " + std::to_string(new_state->index().val) + "; current epoch is " + std::to_string(new_state->epoch())); - roster_map ret = replace_state(std::make_unique<::mlspp::State>(std::move(*newState))); + roster_map ret = replace_state(std::make_unique<::mlspp::State>(std::move(*new_state))); // reset the outbound cached group since we handled the commit for this epoch - outboundCachedGroupState_.reset(); - + outbound_cached_group_state.reset(); clear_pending_state(); return ret; @@ -365,46 +357,46 @@ catch (const std::exception& e) { return failed_t{}; } -std::optional session::process_welcome(std::vector welcome, std::set const& recognizedUserIDs) noexcept +std::optional session::process_welcome(std::vector welcome, std::set const& recognised_user_ids) noexcept try { if (!has_cryptographic_state_for_welcome()) { creator.log(dpp::ll_warning, "Missing local crypto state necessary to process MLS welcome"); return std::nullopt; } - if (!externalSender_) { + if (!mls_external_sender) { creator.log(dpp::ll_warning, "Cannot process MLS welcome without an external sender"); return std::nullopt; } - if (currentState_) { + if (current_state) { creator.log(dpp::ll_warning, "Cannot process MLS welcome after joining/creating an MLS group"); return std::nullopt; } // unmarshal the incoming welcome - auto unmarshalledWelcome = ::mlspp::tls::get<::mlspp::Welcome>(welcome); + auto unmarshalled_welcome = ::mlspp::tls::get<::mlspp::Welcome>(welcome); // construct the state from the unmarshalled welcome - auto newState = std::make_unique<::mlspp::State>( - *joinInitPrivateKey_, - *selfHPKEPrivateKey_, - *selfSigPrivateKey_, - *joinKeyPackage_, - unmarshalledWelcome, - std::nullopt, - std::map<::mlspp::bytes_ns::bytes, ::mlspp::bytes_ns::bytes>()); + auto new_state = std::make_unique<::mlspp::State>( + *join_init_private_key, + *hpke_private_key, + *signature_private_key, + *join_key_package, + unmarshalled_welcome, + std::nullopt, + std::map<::mlspp::bytes_ns::bytes, ::mlspp::bytes_ns::bytes>()); // perform application-level verification of the new state - if (!verify_welcome_state(*newState, recognizedUserIDs)) { + if (!verify_welcome_state(*new_state, recognised_user_ids)) { creator.log(dpp::ll_warning, "Group received in MLS welcome is not valid"); return std::nullopt; } - creator.log(dpp::ll_debug, "Successfully welcomed to MLS Group, our leaf index is " + std::to_string(newState->index().val) + "; current epoch is " + std::to_string(newState->epoch())); + creator.log(dpp::ll_debug, "Successfully welcomed to MLS Group, our leaf index is " + std::to_string(new_state->index().val) + "; current epoch is " + std::to_string(new_state->epoch())); // make the verified state our new (and only) state - roster_map ret = replace_state(std::move(newState)); + roster_map ret = replace_state(std::move(new_state)); // clear out any pending state for creating/joining a group clear_pending_state(); @@ -419,27 +411,22 @@ catch (const std::exception& e) { roster_map session::replace_state(std::unique_ptr<::mlspp::State>&& state) { - roster_map newRoster; + roster_map new_roster; for (const ::mlspp::LeafNode& node : state->roster()) { if (node.credential.type() != ::mlspp::CredentialType::basic) { continue; } const auto& cred = node.credential.template get<::mlspp::BasicCredential>(); - - newRoster[from_big_endian_bytes(cred.identity)] = node.signature_key.data.as_vec(); + new_roster[from_big_endian_bytes(cred.identity)] = node.signature_key.data.as_vec(); } - roster_map changeMap; + roster_map change_map; - std::set_difference(newRoster.begin(), - newRoster.end(), - roster_.begin(), - roster_.end(), - std::inserter(changeMap, changeMap.end())); + std::set_difference(new_roster.begin(), new_roster.end(), roster.begin(), roster.end(), std::inserter(change_map, change_map.end())); - struct MissingItemWrapper { - roster_map& changeMap_; + struct missing_item_wrapper { + roster_map& map; using iterator = roster_map::iterator; using const_iterator = roster_map::const_iterator; @@ -447,37 +434,36 @@ roster_map session::replace_state(std::unique_ptr<::mlspp::State>&& state) iterator insert(const_iterator it, const value_type& value) { - return changeMap_.try_emplace(it, value.first, std::vector{}); + return map.try_emplace(it, value.first, std::vector{}); } - iterator begin() { return changeMap_.begin(); } + iterator begin() { return map.begin(); } - iterator end() { return changeMap_.end(); } + iterator end() { return map.end(); } }; - MissingItemWrapper wrapper{changeMap}; + missing_item_wrapper wrapper{change_map}; - std::set_difference(roster_.begin(), - roster_.end(), - newRoster.begin(), - newRoster.end(), - std::inserter(wrapper, wrapper.end())); + std::set_difference(roster.begin(), + roster.end(), + new_roster.begin(), + new_roster.end(), + std::inserter(wrapper, wrapper.end())); - roster_ = std::move(newRoster); - currentState_ = std::move(state); + roster = std::move(new_roster); + current_state = std::move(state); - return changeMap; + return change_map; } bool session::has_cryptographic_state_for_welcome() const noexcept { - return joinKeyPackage_ && joinInitPrivateKey_ && selfSigPrivateKey_ && selfHPKEPrivateKey_; + return join_key_package && join_init_private_key && signature_private_key && hpke_private_key; } -bool session::verify_welcome_state(::mlspp::State const& state, - std::set const& recognizedUserIDs) const +bool session::verify_welcome_state(::mlspp::State const& state, std::set const& recognised_user_ids) const { - if (!externalSender_) { + if (!mls_external_sender) { creator.log(dpp::ll_warning, "Cannot verify MLS welcome without an external sender"); TRACK_MLS_ERROR("Missing external sender when processing Welcome"); return false; @@ -496,7 +482,7 @@ bool session::verify_welcome_state(::mlspp::State const& state, return false; } - if (ext->senders.front() != *externalSender_) { + if (ext->senders.front() != *mls_external_sender) { creator.log(dpp::ll_warning, "MLS welcome lists unexpected external sender"); TRACK_MLS_ERROR("Welcome message lists unexpected external sender"); return false; @@ -508,7 +494,7 @@ bool session::verify_welcome_state(::mlspp::State const& state, // before all in-flight proposals were handled. for (const auto& leaf : state.roster()) { - if (!is_recognized_user_id(leaf.credential, recognizedUserIDs)) { + if (!is_recognized_user_id(leaf.credential, recognised_user_ids)) { creator.log(dpp::ll_warning, "MLS welcome lists unrecognized user ID"); } } @@ -516,33 +502,33 @@ bool session::verify_welcome_state(::mlspp::State const& state, return true; } -void session::init_leaf_node(std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept +void session::init_leaf_node(std::string const& self_user_id, std::shared_ptr<::mlspp::SignaturePrivateKey>& transient_key) noexcept try { - auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); + auto ciphersuite = ciphersuite_for_protocol_version(session_protocol_version); - if (!transientKey) { - if (!signingKeyId_.empty()) { - transientKey = get_persisted_key_pair(creator, keyPairContext_, signingKeyId_, protocolVersion_); - if (!transientKey) { + if (!transient_key) { + if (!signing_key_id.empty()) { + transient_key = get_persisted_key_pair(creator, key_pair_context, signing_key_id, session_protocol_version); + if (!transient_key) { creator.log(dpp::ll_warning, "Did not receive MLS signature private key from get_persisted_key_pair; aborting"); return; } } else { - transientKey = std::make_shared<::mlspp::SignaturePrivateKey>( + transient_key = std::make_shared<::mlspp::SignaturePrivateKey>( ::mlspp::SignaturePrivateKey::generate(ciphersuite)); } } - selfSigPrivateKey_ = transientKey; - - auto selfCredential = create_user_credential(selfUserId, protocolVersion_); + signature_private_key = transient_key; - selfHPKEPrivateKey_ = std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); - - selfLeafNode_ = std::make_unique<::mlspp::LeafNode>(ciphersuite, selfHPKEPrivateKey_->public_key, selfSigPrivateKey_->public_key, std::move(selfCredential), - leaf_node_capabilities_for_protocol_version(protocolVersion_), ::mlspp::Lifetime::create_default(), - leaf_node_extensions_for_protocol_version(protocolVersion_), *selfSigPrivateKey_); + auto self_credential = create_user_credential(self_user_id, session_protocol_version); + hpke_private_key = std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); + self_leaf_node = std::make_unique<::mlspp::LeafNode>( + ciphersuite, hpke_private_key->public_key, signature_private_key->public_key, std::move(self_credential), + leaf_node_capabilities_for_protocol_version(session_protocol_version), ::mlspp::Lifetime::create_default(), + leaf_node_extensions_for_protocol_version(session_protocol_version), *signature_private_key + ); creator.log(dpp::ll_debug, "Created MLS leaf node"); } @@ -553,22 +539,14 @@ catch (const std::exception& e) { void session::reset_join_key_package() noexcept try { - if (!selfLeafNode_) { + if (!self_leaf_node) { creator.log(dpp::ll_warning, "Cannot initialize join key package without a leaf node"); return; } - auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); - - joinInitPrivateKey_ = - std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); - - joinKeyPackage_ = - std::make_unique<::mlspp::KeyPackage>(ciphersuite, - joinInitPrivateKey_->public_key, - *selfLeafNode_, - leaf_node_extensions_for_protocol_version(protocolVersion_), - *selfSigPrivateKey_); + auto ciphersuite = ciphersuite_for_protocol_version(session_protocol_version); + join_init_private_key = std::make_unique<::mlspp::HPKEPrivateKey>(::mlspp::HPKEPrivateKey::generate(ciphersuite)); + join_key_package = std::make_unique<::mlspp::KeyPackage>(ciphersuite, join_init_private_key->public_key, *self_leaf_node, leaf_node_extensions_for_protocol_version(session_protocol_version), *signature_private_key); } catch (const std::exception& e) { creator.log(dpp::ll_warning, "Failed to initialize join key package: " + std::string(e.what())); @@ -577,33 +555,32 @@ catch (const std::exception& e) { void session::create_pending_group() noexcept try { - if (groupId_.empty()) { + if (session_group_id.empty()) { creator.log(dpp::ll_warning, "Cannot create MLS group without a group ID"); return; } - if (!externalSender_) { - creator.log(dpp::ll_warning, "Cannot create MLS group without ExternalSender"); + if (!mls_external_sender) { + creator.log(dpp::ll_debug, "Cannot create MLS group without external sender"); return; } - if (!selfLeafNode_) { + if (!self_leaf_node) { creator.log(dpp::ll_warning, "Cannot create MLS group without self leaf node"); return; } creator.log(dpp::ll_debug, "Creating a pending MLS group"); - auto ciphersuite = ciphersuite_for_protocol_version(protocolVersion_); - - pendingGroupState_ = std::make_unique<::mlspp::State>( - groupId_, + auto ciphersuite = ciphersuite_for_protocol_version(session_protocol_version); + pending_group_state = std::make_unique<::mlspp::State>( + session_group_id, ciphersuite, - *selfHPKEPrivateKey_, - *selfSigPrivateKey_, - *selfLeafNode_, - group_extensions_for_protocol_version(protocolVersion_, *externalSender_)); - + *hpke_private_key, + *signature_private_key, + *self_leaf_node, + group_extensions_for_protocol_version(session_protocol_version, *mls_external_sender) + ); creator.log(dpp::ll_debug, "Created a pending MLS group"); } catch (const std::exception& e) { @@ -618,12 +595,12 @@ try { // so every time the client asks for a key package we create a new one reset_join_key_package(); - if (!joinKeyPackage_) { + if (!join_key_package) { creator.log(dpp::ll_warning, "Cannot marshal an uninitialized key package"); return {}; } - return ::mlspp::tls::marshal(*joinKeyPackage_); + return ::mlspp::tls::marshal(*join_key_package); } catch (const std::exception& e) { creator.log(dpp::ll_warning, "Failed to marshal join key package: " + std::string(e.what())); @@ -631,41 +608,39 @@ catch (const std::exception& e) { return {}; } -std::unique_ptr session::get_key_ratchet(std::string const& userId) const noexcept +std::unique_ptr session::get_key_ratchet(std::string const& user_id) const noexcept { - if (!currentState_) { + if (!current_state) { creator.log(dpp::ll_warning, "Cannot get key ratchet without an established MLS group"); return nullptr; } // change the string user ID to a little endian 64 bit user ID - auto u64userId = strtoull(userId.c_str(), nullptr, 10); - auto userIdBytes = ::mlspp::bytes_ns::bytes(sizeof(u64userId)); - memcpy(userIdBytes.data(), &u64userId, sizeof(u64userId)); + // TODO: Make this use dpp::snowflake + auto u64_user_id = strtoull(user_id.c_str(), nullptr, 10); + auto user_id_bytes = ::mlspp::bytes_ns::bytes(sizeof(u64_user_id)); + memcpy(user_id_bytes.data(), &u64_user_id, sizeof(u64_user_id)); // generate the base secret for the hash ratchet - auto baseSecret = - currentState_->do_export(session::USER_MEDIA_KEY_BASE_LABEL, userIdBytes, AES_GCM_128_KEY_BYTES); + auto secret = current_state->do_export(session::USER_MEDIA_KEY_BASE_LABEL, user_id_bytes, AES_GCM_128_KEY_BYTES); - // this assumes the MLS ciphersuite produces a kAesGcm128KeyBytes sized key + // this assumes the MLS ciphersuite produces an AES_GCM_128_KEY_BYTES sized key // would need to be updated to a different ciphersuite if there's a future mismatch - return std::make_unique(creator, currentState_->cipher_suite(), std::move(baseSecret)); + return std::make_unique(creator, current_state->cipher_suite(), std::move(secret)); } -void session::get_pairwise_fingerprint(uint16_t version, - std::string const& userId, - pairwise_fingerprint_callback callback) const noexcept +void session::get_pairwise_fingerprint(uint16_t version, std::string const& user_id, pairwise_fingerprint_callback callback) const noexcept try { - if (!currentState_ || !selfSigPrivateKey_) { + if (!current_state || !signature_private_key) { throw std::invalid_argument("No established MLS group"); } - uint64_t u64RemoteUserId = strtoull(userId.c_str(), nullptr, 10); - uint64_t u64SelfUserId = strtoull(selfUserId_.c_str(), nullptr, 10); + uint64_t remote_user_id = strtoull(user_id.c_str(), nullptr, 10); + uint64_t self_user_id = strtoull(bot_user_id.c_str(), nullptr, 10); - auto it = roster_.find(u64RemoteUserId); - if (it == roster_.end()) { - throw std::invalid_argument("Unknown user ID: " + userId); + auto it = roster.find(remote_user_id); + if (it == roster.end()) { + throw std::invalid_argument("Unknown user ID: " + user_id); } ::mlspp::tls::ostream toHash1; @@ -673,11 +648,11 @@ try { toHash1 << version; toHash1.write_raw(it->second); - toHash1 << u64RemoteUserId; + toHash1 << remote_user_id; toHash2 << version; - toHash2.write_raw(selfSigPrivateKey_->public_key.data); - toHash2 << u64SelfUserId; + toHash2.write_raw(signature_private_key->public_key.data); + toHash2 << self_user_id; std::vector> keyData = { toHash1.bytes(), @@ -725,8 +700,7 @@ try { if (ret == 1) { callback(out); - } - else { + } else { callback({}); } }).detach(); @@ -738,20 +712,14 @@ catch (const std::exception& e) { void session::clear_pending_state() { - pendingGroupState_.reset(); - pendingGroupCommit_.reset(); - - joinInitPrivateKey_.reset(); - joinKeyPackage_.reset(); - - selfHPKEPrivateKey_.reset(); - - selfLeafNode_.reset(); - - stateWithProposals_.reset(); - proposalQueue_.clear(); + pending_group_state.reset(); + pending_group_commit.reset(); + join_init_private_key.reset(); + join_key_package.reset(); + hpke_private_key.reset(); + self_leaf_node.reset(); + state_with_proposals.reset(); + proposal_queue.clear(); } -} // namespace dpp::dave::mls - - +} diff --git a/src/dpp/dave/session.h b/src/dpp/dave/session.h index da488bb895..93851b3ee5 100755 --- a/src/dpp/dave/session.h +++ b/src/dpp/dave/session.h @@ -47,7 +47,7 @@ namespace mlspp { struct MLSMessage; struct SignaturePrivateKey; class State; -} // namespace mlspp +} namespace dpp { class cluster; @@ -70,10 +70,10 @@ class session { // NOLINT /** * @brief Constructor * @param context key pair context (set to nullptr to use a transient key pair) - * @param authSessionId auth session id (set to empty string to use a transient key pair) + * @param auth_session_id auth session id (set to empty string to use a transient key pair) * @param callback callback for failure */ - session(dpp::cluster& cluster, key_pair_context_type context, const std::string& authSessionId, mls_failure_callback callback) noexcept; + session(dpp::cluster& cluster, key_pair_context_type context, const std::string& auth_session_id, mls_failure_callback callback) noexcept; /** * @brief Destructor @@ -86,11 +86,11 @@ class session { // NOLINT * whilst preserving other state set by the constructor. * * @param version protocol version - * @param groupId group id (channel id) - * @param selfUserId bot's user id - * @param transientKey transient private key + * @param group_id group id (channel id) + * @param self_user_id bot's user id + * @param transient_key transient private key */ - void init(protocol_version version, uint64_t groupId, std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept; + void init(protocol_version version, uint64_t group_id, std::string const& self_user_id, std::shared_ptr<::mlspp::SignaturePrivateKey>& transient_key) noexcept; /** * @brief Reset the session to defaults @@ -108,7 +108,7 @@ class session { // NOLINT * @return protocol version */ [[nodiscard]] protocol_version get_protocol_version() const noexcept { - return protocolVersion_; + return session_protocol_version; } /** @@ -119,17 +119,17 @@ class session { // NOLINT /** * @brief Set external sender from external sender opcode - * @param externalSenderPackage external sender package + * @param external_sender_package external sender package */ - void set_external_sender(std::vector const& externalSenderPackage) noexcept; + void set_external_sender(std::vector const& external_sender_package) noexcept; /** * @brief Process proposals from proposals opcode * @param proposals proposals blob from websocket - * @param recognizedUserIDs list of recognised user IDs + * @param recognised_user_ids list of recognised user IDs * @return optional vector to send in reply as commit welcome */ - std::optional> process_proposals(std::vector proposals, std::set const& recognizedUserIDs) noexcept; + std::optional> process_proposals(std::vector proposals, std::set const& recognised_user_ids) noexcept; /** * @brief Process commit message from discord websocket @@ -141,10 +141,10 @@ class session { // NOLINT /** * @brief Process welcome blob * @param welcome welcome blob from discord - * @param recognizedUserIDs Recognised user ID list + * @param recognised_user_ids Recognised user ID list * @return roster list of people in the vc */ - std::optional process_welcome(std::vector welcome, std::set const& recognizedUserIDs) noexcept; + std::optional process_welcome(std::vector welcome, std::set const& recognised_user_ids) noexcept; /** * @brief Get the bot user's key package for sending to websocket @@ -154,10 +154,10 @@ class session { // NOLINT /** * @brief Get key ratchet for a user (including the bot) - * @param userId User id to get ratchet for + * @param user_id User id to get ratchet for * @return The user's key ratchet for use in an encryptor or decryptor */ - [[nodiscard]] std::unique_ptr get_key_ratchet(std::string const& userId) const noexcept; + [[nodiscard]] std::unique_ptr get_key_ratchet(std::string const& user_id) const noexcept; /** * @brief callback for completion of pairwise fingerprint @@ -169,18 +169,18 @@ class session { // NOLINT * @warning This uses SCRYPT and is extremely resource intensive. It will spawn a thread * which will call your callback on completion. * @param version Should always be 0x00 - * @param userId User ID to get fingerprint for + * @param user_id User ID to get fingerprint for * @param callback Callback for completion */ - void get_pairwise_fingerprint(uint16_t version, std::string const& userId, pairwise_fingerprint_callback callback) const noexcept; + void get_pairwise_fingerprint(uint16_t version, std::string const& user_id, pairwise_fingerprint_callback callback) const noexcept; private: /** * @brief Initialise leaf node - * @param selfUserId Bot user id - * @param transientKey Transient key + * @param self_user_id Bot user id + * @param transient_key Transient key */ - void init_leaf_node(std::string const& selfUserId, std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept; + void init_leaf_node(std::string const& self_user_id, std::shared_ptr<::mlspp::SignaturePrivateKey>& transient_key) noexcept; /** * @brief Reset join key @@ -201,27 +201,27 @@ class session { // NOLINT /** * @brief Check if user ID is valid * @param cred MLS credential - * @param recognizedUserIDs list of recognised user IDs + * @param recognised_user_ids list of recognised user IDs * @return */ - [[nodiscard]] bool is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognizedUserIDs) const; + [[nodiscard]] bool is_recognized_user_id(const ::mlspp::Credential& cred, std::set const& recognised_user_ids) const; /** * @brief Validate proposals message * @param message authenticated content message - * @param targetState new state - * @param recognizedUserIDs recognised list of user IDs + * @param target_state new state + * @param recognised_user_ids recognised list of user IDs * @return true if validated */ - [[nodiscard]] bool validate_proposal_message(::mlspp::AuthenticatedContent const& message, ::mlspp::State const& targetState, std::set const& recognizedUserIDs) const; + [[nodiscard]] bool validate_proposal_message(::mlspp::AuthenticatedContent const& message, ::mlspp::State const& target_state, std::set const& recognised_user_ids) const; /** * @brief Verify that welcome state is valid * @param state current state - * @param recognizedUserIDs list of recognised user IDs + * @param recognised_user_ids list of recognised user IDs * @return */ - [[nodiscard]] bool verify_welcome_state(::mlspp::State const& state, std::set const& recognizedUserIDs) const; + [[nodiscard]] bool verify_welcome_state(::mlspp::State const& state, std::set const& recognised_user_ids) const; /** * @brief Check if can process a commit now @@ -247,33 +247,33 @@ class session { // NOLINT */ inline static const std::string USER_MEDIA_KEY_BASE_LABEL = "Discord Secure Frames v0"; - protocol_version protocolVersion_; - std::vector groupId_; - std::string signingKeyId_; - std::string selfUserId_; - key_pair_context_type keyPairContext_{nullptr}; + protocol_version session_protocol_version; + std::vector session_group_id; + std::string signing_key_id; + std::string bot_user_id; + key_pair_context_type key_pair_context{nullptr}; - std::unique_ptr<::mlspp::LeafNode> selfLeafNode_; - std::shared_ptr<::mlspp::SignaturePrivateKey> selfSigPrivateKey_; - std::unique_ptr<::mlspp::HPKEPrivateKey> selfHPKEPrivateKey_; + std::unique_ptr<::mlspp::LeafNode> self_leaf_node; + std::shared_ptr<::mlspp::SignaturePrivateKey> signature_private_key; + std::unique_ptr<::mlspp::HPKEPrivateKey> hpke_private_key; - std::unique_ptr<::mlspp::HPKEPrivateKey> joinInitPrivateKey_; - std::unique_ptr<::mlspp::KeyPackage> joinKeyPackage_; + std::unique_ptr<::mlspp::HPKEPrivateKey> join_init_private_key; + std::unique_ptr<::mlspp::KeyPackage> join_key_package; - std::unique_ptr<::mlspp::ExternalSender> externalSender_; + std::unique_ptr<::mlspp::ExternalSender> mls_external_sender; - std::unique_ptr<::mlspp::State> pendingGroupState_; - std::unique_ptr<::mlspp::MLSMessage> pendingGroupCommit_; + std::unique_ptr<::mlspp::State> pending_group_state; + std::unique_ptr<::mlspp::MLSMessage> pending_group_commit; - std::unique_ptr<::mlspp::State> outboundCachedGroupState_; + std::unique_ptr<::mlspp::State> outbound_cached_group_state; - std::unique_ptr<::mlspp::State> currentState_; - roster_map roster_; + std::unique_ptr<::mlspp::State> current_state; + roster_map roster; - std::unique_ptr<::mlspp::State> stateWithProposals_; - std::list proposalQueue_; + std::unique_ptr<::mlspp::State> state_with_proposals; + std::list proposal_queue; - mls_failure_callback onMLSFailureCallback_{}; + mls_failure_callback failure_callback{}; /** * @brief DPP Cluster, used for logging @@ -281,6 +281,4 @@ class session { // NOLINT dpp::cluster& creator; }; -} // namespace dpp::dave::mls - - +} diff --git a/src/dpp/dave/user_credential.cpp b/src/dpp/dave/user_credential.cpp index f5fd9a6493..49cfefcaef 100755 --- a/src/dpp/dave/user_credential.cpp +++ b/src/dpp/dave/user_credential.cpp @@ -28,12 +28,11 @@ namespace dpp::dave::mls { -::mlspp::Credential create_user_credential(const std::string& userId, protocol_version version) { +::mlspp::Credential create_user_credential(const std::string& user_id, protocol_version version) { // convert the string user ID to a big endian uint64_t - auto userID = std::stoull(userId); - auto credentialBytes = big_endian_bytes_from(userID); - - return ::mlspp::Credential::basic(credentialBytes); + auto id = std::stoull(user_id); + auto credential_bytes = big_endian_bytes_from(id); + return ::mlspp::Credential::basic(credential_bytes); } std::string user_credential_to_string(const ::mlspp::Credential& cred, protocol_version version) { @@ -42,12 +41,10 @@ std::string user_credential_to_string(const ::mlspp::Credential& cred, protocol_ } const auto& basic = cred.template get<::mlspp::BasicCredential>(); - - auto uidVal = from_big_endian_bytes(basic.identity); - - return std::to_string(uidVal); + auto uid_val = from_big_endian_bytes(basic.identity); + return std::to_string(uid_val); } -} // namespace dpp::dave::mls +} diff --git a/src/dpp/dave/user_credential.h b/src/dpp/dave/user_credential.h index 1afa2b7c3b..3fecf70bdd 100755 --- a/src/dpp/dave/user_credential.h +++ b/src/dpp/dave/user_credential.h @@ -32,11 +32,11 @@ namespace dpp::dave::mls { /** * @brief Create user credentials - * @param userId user id + * @param user_id user id * @param version protocol version * @return */ -::mlspp::Credential create_user_credential(const std::string& userId, protocol_version version); +::mlspp::Credential create_user_credential(const std::string& user_id, protocol_version version); /** * @brief Convert user credentials to string @@ -46,6 +46,5 @@ ::mlspp::Credential create_user_credential(const std::string& userId, protocol_v */ std::string user_credential_to_string(const ::mlspp::Credential& cred, protocol_version version); -} // namespace dpp::dave::mls - +} diff --git a/src/dpp/dave/util.cpp b/src/dpp/dave/util.cpp index 1abdcc2faf..d8e8929b72 100755 --- a/src/dpp/dave/util.cpp +++ b/src/dpp/dave/util.cpp @@ -49,6 +49,4 @@ uint64_t from_big_endian_bytes(const ::mlspp::bytes_ns::bytes& buffer) noexcept return val; } -} // namespace dpp::dave::mls - - +} diff --git a/src/dpp/dave/util.h b/src/dpp/dave/util.h index f351f45feb..3ecdf4dae7 100755 --- a/src/dpp/dave/util.h +++ b/src/dpp/dave/util.h @@ -43,6 +43,4 @@ ::mlspp::bytes_ns::bytes big_endian_bytes_from(uint64_t value) noexcept; */ uint64_t from_big_endian_bytes(const ::mlspp::bytes_ns::bytes& value) noexcept; -} // namespace dpp::dave::mls - - +} diff --git a/src/dpp/dave/version.cpp b/src/dpp/dave/version.cpp index 34a5ac8269..8fe703a41b 100755 --- a/src/dpp/dave/version.cpp +++ b/src/dpp/dave/version.cpp @@ -28,10 +28,8 @@ namespace dpp::dave { constexpr protocol_version current_dave_protocol_version = 1; -protocol_version max_protocol_version() -{ +protocol_version max_protocol_version() { return current_dave_protocol_version; } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/version.h b/src/dpp/dave/version.h index 6c554c2ef0..972940a769 100755 --- a/src/dpp/dave/version.h +++ b/src/dpp/dave/version.h @@ -44,5 +44,4 @@ using signature_version = uint8_t; */ protocol_version max_protocol_version(); -} // namespace dpp::dave - +} From 84141aa0523f4f6e10b9c5f6472e88870839d310 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Wed, 16 Oct 2024 17:18:44 +0100 Subject: [PATCH 77/99] docs: add docblock comments to all libdave class variables (#1286) --- src/dpp/dave/array_view.h | 3 +- src/dpp/dave/cipher_interface.cpp | 3 +- src/dpp/dave/cipher_interface.h | 3 +- src/dpp/dave/clock.h | 3 +- src/dpp/dave/codec_utils.cpp | 12 ++-- src/dpp/dave/codec_utils.h | 4 +- src/dpp/dave/cryptor_manager.h | 33 ++++++++++ src/dpp/dave/decryptor.h | 24 ++++++++ src/dpp/dave/encryptor.cpp | 9 ++- src/dpp/dave/encryptor.h | 60 +++++++++++++++++- src/dpp/dave/frame_processors.cpp | 17 +++--- src/dpp/dave/frame_processors.h | 56 ++++++++++++++++- src/dpp/dave/leb128.cpp | 2 +- src/dpp/dave/parameters.h | 2 +- src/dpp/dave/persisted_key_pair_generic.cpp | 2 +- src/dpp/dave/session.h | 67 +++++++++++++++++++++ src/dpp/voice/enabled/discover_ip.cpp | 6 +- 17 files changed, 270 insertions(+), 36 deletions(-) diff --git a/src/dpp/dave/array_view.h b/src/dpp/dave/array_view.h index b5752e83d7..e1e9c18c80 100755 --- a/src/dpp/dave/array_view.h +++ b/src/dpp/dave/array_view.h @@ -116,5 +116,4 @@ inline array_view make_array_view(std::vector& data) return array_view(data.data(), data.size()); } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/cipher_interface.cpp b/src/dpp/dave/cipher_interface.cpp index 140debcbc3..58784c51bc 100755 --- a/src/dpp/dave/cipher_interface.cpp +++ b/src/dpp/dave/cipher_interface.cpp @@ -34,5 +34,4 @@ std::unique_ptr create_cipher(dpp::cluster& cl, const encrypti return cipher->is_valid() ? std::move(cipher) : nullptr; } -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/cipher_interface.h b/src/dpp/dave/cipher_interface.h index ea99e0c554..44004883e8 100755 --- a/src/dpp/dave/cipher_interface.h +++ b/src/dpp/dave/cipher_interface.h @@ -99,5 +99,4 @@ class cipher_interface { // NOLINT */ std::unique_ptr create_cipher(dpp::cluster& cl, const encryption_key& key); -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/clock.h b/src/dpp/dave/clock.h index c8a2ab6872..db93afd914 100755 --- a/src/dpp/dave/clock.h +++ b/src/dpp/dave/clock.h @@ -74,5 +74,4 @@ class clock : public clock_interface { } }; -} // namespace dpp::dave - +} diff --git a/src/dpp/dave/codec_utils.cpp b/src/dpp/dave/codec_utils.cpp index 85c8469412..3cae886066 100755 --- a/src/dpp/dave/codec_utils.cpp +++ b/src/dpp/dave/codec_utils.cpp @@ -31,8 +31,7 @@ namespace dpp::dave::codec_utils { -unencrypted_frame_header_size BytesCoveringH264PPS(const uint8_t* payload, const uint64_t size_remaining) -{ +unencrypted_frame_header_size bytes_covering_h264_pps(const uint8_t* payload, const uint64_t size_remaining) { // the payload starts with three exponential golomb encoded values // (first_mb_in_slice, sps_id, pps_id) // the depacketizer needs the pps_id unencrypted @@ -77,7 +76,12 @@ unencrypted_frame_header_size BytesCoveringH264PPS(const uint8_t* payload, const } // return the number of bytes that covers the last exp golomb encoded value - return (payload_bit_index / 8) + 1; + auto result = (payload_bit_index / 8) + 1; + if (result > std::numeric_limits::max()) { + // bytes covering H264 PPS result cannot fit into unencrypted frame header size + return 0; + } + return static_cast(result); } const uint8_t nalu_long_start_code[] = {0, 0, 0, 1}; @@ -208,7 +212,7 @@ bool process_frame_h264(outbound_frame_processor& processor, array_view frame); -} // namespace dpp::dave::codec_utils - - +} diff --git a/src/dpp/dave/cryptor_manager.h b/src/dpp/dave/cryptor_manager.h index 88d2454e4c..731c145234 100755 --- a/src/dpp/dave/cryptor_manager.h +++ b/src/dpp/dave/cryptor_manager.h @@ -149,16 +149,49 @@ class aead_cipher_manager { */ void cleanup_expired_ciphers(); + /** + * @brief chrono clock + */ const clock_interface& current_clock; + + /** + * @brief key ratchet for cryptor + */ std::unique_ptr current_key_ratchet; + + /** + * @brief Cryptor for each generation with expiry + */ std::unordered_map cryptor_generations; + /** + * @brief Time ratchet was created + */ time_point ratchet_creation; + + /** + * @brief Time ratchet expired + */ time_point ratchet_expiry; + + /** + * @brief Oldest generation for ratchet + */ key_generation oldest_generation{0}; + + /** + * @brief Newest generation for ratchet + */ key_generation newest_generation{0}; + /** + * @brief Newest nonce + */ std::optional newest_processed_nonce; + + /** + * @brief List of missing nonces from sequence + */ std::deque missing_nonces; /** diff --git a/src/dpp/dave/decryptor.h b/src/dpp/dave/decryptor.h index bdf7718ee6..e093dc46fb 100755 --- a/src/dpp/dave/decryptor.h +++ b/src/dpp/dave/decryptor.h @@ -177,15 +177,39 @@ class decryptor { */ void return_frame_processor(std::unique_ptr frame_processor); + /** + * @brief Chrono clock + */ clock current_clock; + + /** + * @brief Cryptor manager list + */ std::deque cryptor_managers; + /** + * @brief Mutex for thread safety of frame processor list + */ std::mutex frame_processors_mutex; + + /** + * @brief List of frame processors + */ std::vector> frame_processors; + /** + * @brief Passthrough expiry time + */ time_point allow_pass_through_until{time_point::min()}; + /** + * @brief Last stats generation time + */ time_point last_stats_time{time_point::min()}; + + /** + * @brief Stats for audio and video decryption + */ std::array stats; /** diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp index 716332977b..782d02984a 100755 --- a/src/dpp/dave/encryptor.cpp +++ b/src/dpp/dave/encryptor.cpp @@ -164,7 +164,14 @@ encryptor::result_code encryptor::encrypt(media_type this_media_type, uint32_t s } // write the supplemental bytes size - supplemental_bytes_size supplemental_bytes = SUPPLEMENTAL_BYTES + size + ranges_size; + uint64_t supplemental_bytes_large = SUPPLEMENTAL_BYTES + size + ranges_size; + + if (supplemental_bytes_large > std::numeric_limits::max()) { + result = rc_encryption_failure; + break; + } + + supplemental_bytes_size supplemental_bytes = supplemental_bytes_large; std::memcpy(supplemental_bytes_buffer.data(), &supplemental_bytes, sizeof(supplemental_bytes_size)); // write the marker bytes, ends the frame diff --git a/src/dpp/dave/encryptor.h b/src/dpp/dave/encryptor.h index d5ec5e8c23..6b327c83ff 100755 --- a/src/dpp/dave/encryptor.h +++ b/src/dpp/dave/encryptor.h @@ -77,9 +77,9 @@ struct encryption_stats { class encryptor { public: /** - * @brief Constructor - * @param cl Creator - */ + * @brief Constructor + * @param cl Creator + */ encryptor(dpp::cluster& cl) : creator(cl) { }; /** @@ -219,25 +219,79 @@ class encryptor { */ void update_current_protocol_version(protocol_version version); + /** + * @brief True if passthrough is enabled + */ std::atomic_bool passthrough_mode_enable{false}; + /** + * @brief Key generation mutex for thread safety + */ std::mutex key_gen_mutex; + + /** + * @brief Current encryption (send) ratchet + */ std::unique_ptr ratchet; + + /** + * @brief Current encryption cipher + */ std::shared_ptr cryptor; + + /** + * @brief Current key generation number + */ key_generation current_key_generation{0}; + + /** + * @brief Current truncated sync nonce + */ truncated_sync_nonce truncated_nonce{0}; + /** + * @brief Frame processor list mutex + */ std::mutex frame_processors_mutex; + + /** + * @brief List of outbound frame processors + */ std::vector> frame_processors; + /** + * @brief A pair of 32 bit SSRC and codec in use for that SSRC + */ using ssrc_codec_pair = std::pair; + + /** + * @brief List of codec pairs for SSRCs + */ std::vector ssrc_codec_pairs; + /** + * @brief A chrono time point + */ using time_point = std::chrono::time_point; + + /** + * @brief Last time stats were updated + */ time_point last_stats_time{time_point::min()}; + + /** + * @brief Stores audio/video encryption stats + */ std::array stats; + /** + * @brief Callback for version change, if any + */ protocol_version_changed_callback changed_callback; + + /** + * Current protocol version supported + */ protocol_version current_protocol_version{max_protocol_version()}; /** diff --git a/src/dpp/dave/frame_processors.cpp b/src/dpp/dave/frame_processors.cpp index 79ae115693..a8b7aa185e 100755 --- a/src/dpp/dave/frame_processors.cpp +++ b/src/dpp/dave/frame_processors.cpp @@ -59,7 +59,7 @@ namespace dpp::dave { } #endif -std::pair OverflowAdd(size_t a, size_t b) +std::pair overflow_add(size_t a, size_t b) { size_t res; #if defined(_MSC_VER) && defined(_M_X64) @@ -97,10 +97,10 @@ uint8_t serialize_unencrypted_ranges(const ranges& unencrypted_ranges, uint8_t* write_at += write_leb128(range.offset, write_at); write_at += write_leb128(range.size, write_at); } - return write_at - buffer; + return static_cast(write_at - buffer); } -uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const size_t buffer_size, ranges& unencrypted_ranges) +uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const uint8_t buffer_size, ranges& unencrypted_ranges) { auto start = read_at; auto end = read_at + buffer_size; @@ -123,7 +123,7 @@ uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const size_t buf return 0; } - return read_at - start; + return static_cast(read_at - start); } bool validate_unencrypted_ranges(const ranges& unencrypted_ranges, size_t frame_size) @@ -140,7 +140,7 @@ bool validate_unencrypted_ranges(const ranges& unencrypted_ranges, size_t frame_ auto max_end = i + 1 < unencrypted_ranges.size() ? unencrypted_ranges[i + 1].offset : frame_size; - auto [did_overflow, current_end] = OverflowAdd(current.offset, current.size); + auto [did_overflow, current_end] = overflow_add(current.offset, current.size); if (did_overflow || current_end > max_end) { return false; } @@ -197,8 +197,7 @@ void inbound_frame_processor::parse_frame(array_view frame) { clear(); - constexpr auto min_supplemental_bytes_size = - AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); + constexpr auto min_supplemental_bytes_size = AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); if (frame.size() < min_supplemental_bytes_size) { creator.log(dpp::ll_warning, "Encrypted frame is too small to contain min supplemental bytes"); return; @@ -236,14 +235,14 @@ void inbound_frame_processor::parse_frame(array_view frame) auto nonce_buffer = supplemental_bytes_buffer + AES_GCM_127_TRUNCATED_TAG_BYTES; auto read_at = nonce_buffer; auto end = bytes_size_buffer; - truncated_nonce = read_leb128(read_at, end); + truncated_nonce = static_cast(read_leb128(read_at, end)); if (read_at == nullptr) { creator.log(dpp::ll_warning, "Failed to read truncated nonce"); return; } // Read the unencrypted ranges - auto ranges_size = end - read_at; + auto ranges_size = static_cast(end - read_at); deserialize_unencrypted_ranges(read_at, ranges_size, unencrypted_ranges); if (read_at == nullptr) { creator.log(dpp::ll_warning, "Failed to read unencrypted ranges"); diff --git a/src/dpp/dave/frame_processors.h b/src/dpp/dave/frame_processors.h index e7301429c3..0ec4b8e255 100755 --- a/src/dpp/dave/frame_processors.h +++ b/src/dpp/dave/frame_processors.h @@ -73,7 +73,7 @@ uint8_t serialize_unencrypted_ranges(const ranges& unencrypted_ranges, uint8_t* * @param unencrypted_ranges unencrypted ranges to write to * @return size of unencrypted ranges written */ -uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const size_t buffer_size, ranges& unencrypted_ranges); +uint8_t deserialize_unencrypted_ranges(const uint8_t*& read_at, const uint8_t buffer_size, ranges& unencrypted_ranges); /** * @brief Validate unencrypted ranges @@ -183,13 +183,44 @@ class inbound_frame_processor { */ void add_ciphertext_bytes(const uint8_t* data, size_t size); + /** + * @brief True if frames are encrypted + */ bool encrypted{false}; + + /** + * @brief Original size + */ size_t original_size{0}; + + /** + * @brief AEAD tag + */ array_view tag; + + /** + * @brief Truncated nonce + */ truncated_sync_nonce truncated_nonce; + + /** + * @brief Unencrypted parts of the frames + */ ranges unencrypted_ranges; + + /** + * @brief additional authenticated data + */ std::vector authenticated; + + /** + * @brief Ciphertext + */ std::vector ciphertext; + + /** + * @brief Plaintext + */ std::vector plaintext; /** @@ -283,11 +314,34 @@ class outbound_frame_processor { void add_encrypted_bytes(const uint8_t* bytes, size_t size); private: + /** + * @brief Codec used to decrypt + */ codec frame_codec{codec::cd_unknown}; + + /** + * @brief Frame index + */ size_t frame_index{0}; + + /** + * @brief Unencrypted bytes + */ std::vector unencrypted_bytes; + + /** + * @brief Encrypted bytes + */ std::vector encrypted_bytes; + + /** + * @brief Ciphertext bytes + */ std::vector ciphertext_bytes; + + /** + * @brief Unencrypted ranges that need to be kept plaintext to allow for RTP routing + */ ranges unencrypted_ranges; /** diff --git a/src/dpp/dave/leb128.cpp b/src/dpp/dave/leb128.cpp index 414e2ff4b7..f43de97772 100755 --- a/src/dpp/dave/leb128.cpp +++ b/src/dpp/dave/leb128.cpp @@ -76,7 +76,7 @@ size_t write_leb128(uint64_t value, uint8_t* buffer) ++size; value >>= 7; } - buffer[size] = value; + buffer[size] = static_cast(value); ++size; return size; } diff --git a/src/dpp/dave/parameters.h b/src/dpp/dave/parameters.h index 798e8fa03e..ca8590d42d 100755 --- a/src/dpp/dave/parameters.h +++ b/src/dpp/dave/parameters.h @@ -82,4 +82,4 @@ ::mlspp::ExtensionList leaf_node_extensions_for_protocol_version(protocol_versio */ ::mlspp::ExtensionList group_extensions_for_protocol_version(protocol_version version, const ::mlspp::ExternalSender& external_sender) noexcept; -} // namespace dpp::dave::mls +} diff --git a/src/dpp/dave/persisted_key_pair_generic.cpp b/src/dpp/dave/persisted_key_pair_generic.cpp index cf1f056fee..1bc315eda6 100755 --- a/src/dpp/dave/persisted_key_pair_generic.cpp +++ b/src/dpp/dave/persisted_key_pair_generic.cpp @@ -141,7 +141,7 @@ std::shared_ptr<::mlspp::SignaturePrivateKey> get_generic_persisted_key_pair(dpp } #ifdef _WIN32 - int written = _write(fd, newstr.c_str(), newstr.size()); + int written = _write(fd, newstr.c_str(), static_cast(newstr.size())); _close(fd); #else ssize_t written = write(fd, newstr.c_str(), newstr.size()); diff --git a/src/dpp/dave/session.h b/src/dpp/dave/session.h index 93851b3ee5..36e5dabb17 100755 --- a/src/dpp/dave/session.h +++ b/src/dpp/dave/session.h @@ -247,32 +247,99 @@ class session { // NOLINT */ inline static const std::string USER_MEDIA_KEY_BASE_LABEL = "Discord Secure Frames v0"; + /** + * @brief DAVE protocol version for the session + */ protocol_version session_protocol_version; + + /** + * @brief Session group ID (voice channel id) + */ std::vector session_group_id; + + /** + * @brief Signing key id + */ std::string signing_key_id; + + /** + * @brief The bot's user snowflake ID + */ std::string bot_user_id; + + /** + * @brief The bot's key pair context + */ key_pair_context_type key_pair_context{nullptr}; + /** + * @brief Our leaf node in the ratchet tree + */ std::unique_ptr<::mlspp::LeafNode> self_leaf_node; + + /** + * @brief The bots signature private key + */ std::shared_ptr<::mlspp::SignaturePrivateKey> signature_private_key; + + /** + * @brief HPKE private key + */ std::unique_ptr<::mlspp::HPKEPrivateKey> hpke_private_key; + /** + * @brief Private key for join initialisation + */ std::unique_ptr<::mlspp::HPKEPrivateKey> join_init_private_key; + + /** + * @brief Join key package + */ std::unique_ptr<::mlspp::KeyPackage> join_key_package; + /** + * @brief MLS External sender (the discord voice gateway server) + */ std::unique_ptr<::mlspp::ExternalSender> mls_external_sender; + /** + * @brief Pending MLS group state + */ std::unique_ptr<::mlspp::State> pending_group_state; + + /** + * @brief Pending MLS group commit + */ std::unique_ptr<::mlspp::MLSMessage> pending_group_commit; + /** + * @brief Outbound cached group state + */ std::unique_ptr<::mlspp::State> outbound_cached_group_state; + /** + * @brief Current MLS state + */ std::unique_ptr<::mlspp::State> current_state; + + /** + * @brief Participant roster, all users who are in the VC with dave enabled + */ roster_map roster; + /** + * @brief Current state containing proposals + */ std::unique_ptr<::mlspp::State> state_with_proposals; + + /** + * @brief Queue of proposals to process + */ std::list proposal_queue; + /** + * @brief Function to call on failure, if any + */ mls_failure_callback failure_callback{}; /** diff --git a/src/dpp/voice/enabled/discover_ip.cpp b/src/dpp/voice/enabled/discover_ip.cpp index 341be4a80e..7061c20f08 100644 --- a/src/dpp/voice/enabled/discover_ip.cpp +++ b/src/dpp/voice/enabled/discover_ip.cpp @@ -38,13 +38,11 @@ namespace dpp { -/** - * https://discord.com/developers/docs/topics/voice-connections#ip-discovery - */ - /** * @brief Represents an IP discovery packet sent to Discord or received * from Discord. + * + * https://discord.com/developers/docs/topics/voice-connections#ip-discovery */ struct ip_discovery_packet { From f8cff74a9150302dc31b81e0087bc055c81a3aca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 20:17:33 +0100 Subject: [PATCH 78/99] build(deps): bump ubuntu from `ab64a83` to `d4f6f70` (#1284) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e0f58b293f..28c70cdc00 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:ab64a8382e935382638764d8719362bb50ee418d944c1f3d26e0c99fae49a345 +FROM ubuntu:noble@sha256:d4f6f70979d0758d7a6f81e34a61195677f4f4fa576eaf808b79f17499fd93d1 RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From b0d399ae1e43d5e06dfc57e2cdd8a312c711f046 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Thu, 17 Oct 2024 00:44:37 +0100 Subject: [PATCH 79/99] fix: fix broken vcpkg builds which were failing because they were trying to compile as static (#1287) --- CMakeLists.txt | 83 ++++++++++++++++++++++++------------ library-vcpkg/CMakeLists.txt | 23 ++++++---- library/CMakeLists.txt | 2 - mlspp/CMakeLists.txt | 2 +- 4 files changed, 71 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b12fe99ef1..c1a5262c9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,11 +29,14 @@ option(DPP_FORMATTERS "Support for C++20 formatters" OFF) option(DPP_USE_EXTERNAL_JSON "Use an external installation of nlohmann::json" OFF) option(DPP_USE_PCH "Use precompiled headers to speed up compilation" OFF) option(AVX_TYPE "Force AVX type for speeding up audio mixing" OFF) +option(DPP_TEST_VCPKG "Force VCPKG build without VCPKG installed (for development use only!)" OFF) include(CheckCXXSymbolExists) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_compile_definitions(DPP_BUILD) +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/colour.cmake") + set(DPP_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) file(READ "${DPP_ROOT_PATH}/include/dpp/version.h" version_h) @@ -50,10 +53,14 @@ string(CONCAT DPP_VERSION "${DPP_VERSION_MAJOR}.${DPP_VERSION_MINOR}.${DPP_VERSI set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${DPP_ROOT_PATH}/cmake/") -if (DPP_NO_VCPKG) - message("-- INFO: Explicitly disabling VCPKG as running inside the CI action.") +if (DPP_TEST_VCPKG) + message("-- ${Red}DEVELOPER WARNING${ColourReset}: Running in ${Red}VCPKG test mode${ColourReset}: EMULATING A VCPKG BUILD WITHOUT VCPKG") else() - message("-- INFO: Using VCPKG if detected") + if (DPP_NO_VCPKG) + message("-- INFO: Explicitly disabling VCPKG as running inside the CI action.") + else() + message("-- INFO: Using VCPKG if detected") + endif() endif() if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS) @@ -61,14 +68,14 @@ if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS) configure_file("${DPP_ROOT_PATH}/src/dpp/dpp.rc.in" "${DPP_ROOT_PATH}/src/dpp/dpp.rc" NEWLINE_STYLE WIN32) endif() -if (NOT DPP_NO_VCPKG AND EXISTS "${_VCPKG_ROOT_DIR}") +if (DPP_TEST_VCPKG) set(PROJECT_NAME "dpp") project( - "${PROJECT_NAME}" - VERSION "${DPP_VERSION}" - LANGUAGES CXX - HOMEPAGE_URL "https://dpp.dev/" - DESCRIPTION "An incredibly lightweight C++ Discord library." + "${PROJECT_NAME}" + VERSION "${DPP_VERSION}" + LANGUAGES CXX + HOMEPAGE_URL "https://dpp.dev/" + DESCRIPTION "An incredibly lightweight C++ Discord library." ) if (MSVC AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -82,25 +89,47 @@ if (NOT DPP_NO_VCPKG AND EXISTS "${_VCPKG_ROOT_DIR}") add_subdirectory(library-vcpkg) else() - set(PROJECT_NAME "libdpp") - project( - "${PROJECT_NAME}" - VERSION "${DPP_VERSION}" - LANGUAGES CXX - HOMEPAGE_URL "https://dpp.dev/" - DESCRIPTION "An incredibly lightweight C++ Discord library." - ) - - if (MSVC AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(DPP_CLANG_CL true) + if (NOT DPP_NO_VCPKG AND EXISTS "${_VCPKG_ROOT_DIR}") + set(PROJECT_NAME "dpp") + project( + "${PROJECT_NAME}" + VERSION "${DPP_VERSION}" + LANGUAGES CXX + HOMEPAGE_URL "https://dpp.dev/" + DESCRIPTION "An incredibly lightweight C++ Discord library." + ) + + if (MSVC AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(DPP_CLANG_CL true) + endif() + + # Required before we add any subdirectories. + if (DPP_BUILD_TEST) + enable_testing(${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + add_subdirectory(library-vcpkg) + else() + set(PROJECT_NAME "libdpp") + project( + "${PROJECT_NAME}" + VERSION "${DPP_VERSION}" + LANGUAGES CXX + HOMEPAGE_URL "https://dpp.dev/" + DESCRIPTION "An incredibly lightweight C++ Discord library." + ) + + if (MSVC AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(DPP_CLANG_CL true) + endif() + + # Required before we add any subdirectories. + if (DPP_BUILD_TEST) + enable_testing(${CMAKE_CURRENT_SOURCE_DIR}) + endif() + + add_subdirectory(library) endif() - - # Required before we add any subdirectories. - if (DPP_BUILD_TEST) - enable_testing(${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - add_subdirectory(library) endif() find_package(Filesystem) diff --git a/library-vcpkg/CMakeLists.txt b/library-vcpkg/CMakeLists.txt index 16df61f4f5..5e7b9ae6d7 100644 --- a/library-vcpkg/CMakeLists.txt +++ b/library-vcpkg/CMakeLists.txt @@ -18,14 +18,12 @@ add_compile_definitions(HAVE_VOICE) -file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${modules_dir}/dpp/voice/enabled/*.cpp" "${DPP_ROOT_PATH}/dpp/dave/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") +file(GLOB THE_SOURCES "${DPP_ROOT_PATH}/src/dpp/events/*.cpp" "${DPP_ROOT_PATH}/src/dpp/voice/enabled/*.cpp" "${DPP_ROOT_PATH}/src/dpp/dave/*.cpp" "${DPP_ROOT_PATH}/src/dpp/cluster/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.cpp" "${DPP_ROOT_PATH}/src/dpp/*.rc") set(LIB_NAME "${PROJECT_NAME}") -if(WIN32) - add_library("${LIB_NAME}" SHARED "${THE_SOURCES}") -else() - add_library("${LIB_NAME}" STATIC "${THE_SOURCES}") +add_library("${LIB_NAME}" SHARED "${THE_SOURCES}") +if(NOT WIN32) find_package(Threads REQUIRED) endif() @@ -55,6 +53,8 @@ if(WIN32) set(OPENSSL_VERSION "1.1.1f") endif() + + target_compile_options( "${LIB_NAME}" PUBLIC @@ -62,8 +62,8 @@ target_compile_options( PRIVATE "$<$:$<$:/sdl;/Od;/DEBUG;/MP;/DFD_SETSIZE=1024>>" "$<$:$<$:/O2;/Oi;/Oy;/GL;/Gy;/sdl;/MP;/DFD_SETSIZE=1024>>" - "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" - "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" + "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-deprecated-declarations;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" + "$<$:$<$:-fPIC;-Wall;-Wempty-body;-Wno-deprecated-declarations;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" "${AVX_FLAG}" ) @@ -82,6 +82,7 @@ target_include_directories( "$" ) +find_package(OpenSSL REQUIRED) add_subdirectory("${DPP_ROOT_PATH}/mlspp" "mlspp") include_directories("${DPP_ROOT_PATH}/mlspp/include") include_directories("${DPP_ROOT_PATH}/mlspp/lib/bytes/include") @@ -99,8 +100,12 @@ target_link_options( ) find_package(nlohmann_json CONFIG REQUIRED) -find_package(OpenSSL REQUIRED) -find_package(Opus CONFIG REQUIRED) +if (DPP_TEST_VCPKG) + include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindOpus.cmake") + find_package(Opus REQUIRED) +else() + find_package(Opus CONFIG REQUIRED) +endif() find_package(ZLIB REQUIRED) target_link_libraries( diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 0cabd74161..840807669d 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -291,8 +291,6 @@ foreach (fullmodname ${subdirlist}) endif() endforeach() - - target_compile_features(dpp PUBLIC cxx_std_17) target_compile_features(dpp PRIVATE cxx_constexpr) target_compile_features(dpp PRIVATE cxx_auto_type) diff --git a/mlspp/CMakeLists.txt b/mlspp/CMakeLists.txt index d019e83f39..52f26b5ba6 100755 --- a/mlspp/CMakeLists.txt +++ b/mlspp/CMakeLists.txt @@ -40,7 +40,7 @@ include(CMakePackageConfigHelpers) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - add_compile_options(-Wall) + add_compile_options(-Wall -fPIC) elseif(MSVC) add_compile_options(/W2) add_definitions(-DWINDOWS) From fb2b9d9afa8edd073734f196d8c50bbdf09f05b3 Mon Sep 17 00:00:00 2001 From: Ashlynn <37787862+Ashthetik@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:07:20 +1100 Subject: [PATCH 80/99] doc: Extend Coroutine Documentation (#1288) --- docpages/example_programs/using_coroutines/coro_introduction.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docpages/example_programs/using_coroutines/coro_introduction.md b/docpages/example_programs/using_coroutines/coro_introduction.md index e91a4a271e..0e51c1b3cb 100644 --- a/docpages/example_programs/using_coroutines/coro_introduction.md +++ b/docpages/example_programs/using_coroutines/coro_introduction.md @@ -18,3 +18,5 @@ When using a `co_*` function such as `co_message_create`, the request is sent im You may hear that coroutines are "writing async code as if it was sync", while this is sort of correct, it may limit your understanding and especially the dangers of coroutines. I find **they are best thought of as a shortcut for a state machine**, if you've ever written one, you know what this means. Think of the lambda as *its constructor*, in which captures are variable parameters. Think of the parameters passed to your lambda as data members in your state machine. When you `co_await` something, the state machine's function exits, the program goes back to the caller, at this point the calling function may return. References are kept as references in the state machine, which means by the time the state machine is resumed, the reference may be dangling: \ref lambdas-and-locals "this is not good"! Another way to think of them is just like callbacks but keeping the current scope intact. In fact this is exactly what it is, the co_* functions call the normal API calls, with a callback that resumes the coroutine, *in the callback thread*. This means you cannot rely on thread_local variables and need to keep in mind concurrency issues with global states, as your coroutine will be resumed in another thread than the one it started on. + +It is also worth noting that coroutines can lead to cases where errors may fall through and remain uncaptured, requiring the user to manually handle the error. These exceptions occur because callbacks cannot be used in their typical manner, which can be observed [in the following issue](https://github.com/brainboxdotcc/DPP/issues/1222) and the \ref coro-simple-commands "sample coroutine code". From 72258891a301aab95c437676392eae84269b17ae Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Thu, 17 Oct 2024 18:05:00 +0100 Subject: [PATCH 81/99] style: clang-format file, for discussion (#1277) --- .clang-format | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..01b4f5f946 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -8 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: No +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: BeforeHash +IndentWidth: 8 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 8 +UseTab: ForContinuationAndIndentation From 0451aed67d8e2e5c42535edec33679730f4a6d26 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Fri, 18 Oct 2024 02:43:25 +0100 Subject: [PATCH 82/99] Delete .circleci directory --- .circleci/config.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index ae375b935b..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: 2 - -jobs: - build: - docker: - - image: "debian:bullseye" - steps: - - checkout - - run: - name: Installing build dependencies - command: 'apt-get update && apt-get install -y sudo gcc g++ build-essential git cmake libssl-dev zlib1g-dev' - - run: - name: Creating Build Files - command: 'cmake -H. -Bbuild' - - run: - name: Creating Binary Files - command: 'cmake --build build' - - run: - name: Testing installation - command: 'cmake --build build --target install' From 9d68851304d3dbf9cec5a92fc34bd5847fcf0c02 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Fri, 18 Oct 2024 02:43:59 +0100 Subject: [PATCH 83/99] Delete .circleci directory --- .circleci/config.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index ae375b935b..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,20 +0,0 @@ -version: 2 - -jobs: - build: - docker: - - image: "debian:bullseye" - steps: - - checkout - - run: - name: Installing build dependencies - command: 'apt-get update && apt-get install -y sudo gcc g++ build-essential git cmake libssl-dev zlib1g-dev' - - run: - name: Creating Build Files - command: 'cmake -H. -Bbuild' - - run: - name: Creating Binary Files - command: 'cmake --build build' - - run: - name: Testing installation - command: 'cmake --build build --target install' From 0362ef4fa3211031ab07eb3a4973322ca8985f88 Mon Sep 17 00:00:00 2001 From: Matteo Lorenzo Nasci Date: Fri, 18 Oct 2024 17:58:25 +0200 Subject: [PATCH 84/99] Added NOMINMAX to CMakeLists.txt (#1292) --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1a5262c9c..31b14d70ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(DPP_TEST_VCPKG "Force VCPKG build without VCPKG installed (for developmen include(CheckCXXSymbolExists) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_compile_definitions(DPP_BUILD) +add_compile_definitions(NOMINMAX) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/colour.cmake") @@ -150,4 +151,4 @@ endif() if (NOT WIN32) target_link_libraries(dpp PRIVATE std::filesystem) -endif() \ No newline at end of file +endif() From 626157e621cc4ebd63065e186dab67a2250f3fa9 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Fri, 18 Oct 2024 20:10:28 +0100 Subject: [PATCH 85/99] fix: fix broken static builds (#1290) --- cmake/FindOpus.cmake | 3 +- include/dpp/isa/fallback.h | 1 + library/CMakeLists.txt | 98 ++++++++++++++++++++++++++------------ 3 files changed, 71 insertions(+), 31 deletions(-) diff --git a/cmake/FindOpus.cmake b/cmake/FindOpus.cmake index ba23166985..a34553f73a 100644 --- a/cmake/FindOpus.cmake +++ b/cmake/FindOpus.cmake @@ -18,7 +18,8 @@ endif() if(OPUS_LIBRARIES) if(OPUS_USE_STATIC_LIBS) - find_library(LIBM NAMES "libm.a" "libm.tbd") + # on linux with glibc you CANT statically link libm without statically linking all of glibc. DONT DO IT. + #find_library(LIBM NAMES "libm.a" "libm.tbd") else() find_library(LIBM NAMES m) endif() diff --git a/include/dpp/isa/fallback.h b/include/dpp/isa/fallback.h index 87a219f053..a7154233b2 100644 --- a/include/dpp/isa/fallback.h +++ b/include/dpp/isa/fallback.h @@ -20,6 +20,7 @@ ************************************************************************************/ #pragma once +#include #include #include #include diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 840807669d..d631d61f31 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -48,6 +48,27 @@ STRING(REPLACE "AVX" "" AVX_TYPE ${AVX_TYPE}) add_compile_definitions(AVX_TYPE=${AVX_TYPE}) add_compile_options(${AVX_FLAG}) +if(NOT BUILD_SHARED_LIBS) + if(UNIX) + message("-- Building ${Green}static${ColourReset} library.") + + if(UNIX AND NOT APPLE) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + message("-- INFO: Changed lib suffix to ${CMAKE_FIND_LIBRARY_SUFFIXES}") + endif() + + set(OPENSSL_USE_STATIC_LIBS TRUE) + set(OPUS_USE_STATIC_LIBS TRUE) + + else() + message(WARNING "-- Building of static library not supported on non UNIX systems.") + endif() +else() + message("-- Building ${Green}dynamic${ColourReset} library.") +endif() + + + if(WIN32 AND NOT MINGW) # Fake an ssl version number to satisfy MLSPP set(OPENSSL_VERSION "1.1.1f") @@ -109,21 +130,6 @@ if (UNIX) endif() endif() -if(NOT BUILD_SHARED_LIBS) - if(UNIX) - message("-- Building static library.") - - if(UNIX AND NOT APPLE) - set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") - endif() - - set(OPENSSL_USE_STATIC_LIBS ON) - set(OPUS_USE_STATIC_LIBS TRUE) - else() - message(WARNING "-- Building of static library not supported on non UNIX systems.") - endif() -endif() - if (BUILD_VOICE_SUPPORT) if (MINGW OR NOT WIN32) include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindOpus.cmake") @@ -151,6 +157,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) if(MINGW OR NOT WIN32) find_package(ZLIB REQUIRED) + message("-- ZLIB: ${Green}${ZLIB_LIBRARIES}${ColourReset}") endif(MINGW OR NOT WIN32) if(APPLE) @@ -162,6 +169,9 @@ if(APPLE) find_package(OpenSSL REQUIRED) else() if(MINGW OR NOT WIN32) + if(NOT BUILD_SHARED_LIBS) + set(OPENSSL_USE_STATIC_LIBS TRUE) + endif() find_package(OpenSSL REQUIRED) endif() endif() @@ -274,23 +284,35 @@ foreach (fullmodname ${subdirlist}) endif () endif() - if (HAVE_VOICE) - # Private statically linked dependencies - target_link_libraries(${modname} PRIVATE - mlspp - mls_vectors - bytes - tls_syntax - hpke - ) - endif() - if (HAVE_VOICE) target_link_libraries(${modname} PUBLIC ${OPUS_LIBRARIES}) include_directories(${OPUS_INCLUDE_DIRS}) endif() endforeach() +if (HAVE_VOICE) + # Private statically linked dependencies + if(NOT BUILD_SHARED_LIBS AND NOT APPLE) + target_link_libraries(dpp PRIVATE + mlspp.a + mls_vectors.a + bytes.a + tls_syntax.a + hpke.a + ) + message("-- INFO: Linking static dependencies") + else() + target_link_libraries(dpp PRIVATE + mlspp + mls_vectors + bytes + tls_syntax + hpke + ) + message("-- INFO: Linking dynamic dependencies") + endif() +endif() + target_compile_features(dpp PUBLIC cxx_std_17) target_compile_features(dpp PRIVATE cxx_constexpr) target_compile_features(dpp PRIVATE cxx_auto_type) @@ -367,6 +389,22 @@ if(DPP_FORMATTERS) target_compile_definitions(dpp PUBLIC DPP_FORMATTERS) endif() +if (NOT BUILD_SHARED_LIBS) + add_library(dppstatic STATIC + $ + $ + $ + $ + $ + $ + ) + if (HAVE_VOICE) + target_link_libraries(dppstatic ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES} ${OPUS_LIBRARIES} -static-libgcc -static-libstdc++) + else() + target_link_libraries(dppstatic ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}) + endif() +endif() + if (DPP_BUILD_TEST) enable_testing(${CMAKE_CURRENT_SOURCE_DIR}/..) file(GLOB testnamelist "${CMAKE_CURRENT_SOURCE_DIR}/../src/*") @@ -385,11 +423,11 @@ if (DPP_BUILD_TEST) if (MSVC) target_compile_options(${testname} PRIVATE /utf-8) endif() - set (static_if_needed "") - if(NOT BUILD_SHARED_LIBS) - set (static_if_needed "-static") + if(BUILD_SHARED_LIBS) + target_link_libraries(${testname} PUBLIC ${modname}) + else() + target_link_libraries(${testname} PUBLIC dppstatic) endif() - target_link_libraries(${testname} PUBLIC ${modname} ${static_if_needed}) endif() endforeach() add_test( From 73c4751613ee44116820571e6ffa26b7b013dc37 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 19 Oct 2024 10:34:31 +0200 Subject: [PATCH 86/99] feat: added approximate_user_install_count field to application (#1293) --- include/dpp/application.h | 5 +++++ src/dpp/application.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/include/dpp/application.h b/include/dpp/application.h index eb7e8b32df..f49dd9735a 100644 --- a/include/dpp/application.h +++ b/include/dpp/application.h @@ -325,6 +325,11 @@ class DPP_EXPORT application : public managed, public json_interfacecontains("redirect_uris")) { for (const auto& uri : (*j)["redirect_uris"]) { From 71ae2c41f8ff43a1f449b68c1261ce61cb193ce0 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 19 Oct 2024 17:36:27 +0200 Subject: [PATCH 87/99] feat: added endpoints to fetch a user's voice state (#1294) --- include/dpp/cluster.h | 25 +++++++++++++++++++++-- include/dpp/cluster_coro_calls.h | 27 ++++++++++++++++++++++-- include/dpp/cluster_sync_calls.h | 35 ++++++++++++++++++++++++++++++-- include/dpp/restresults.h | 1 + src/dpp/cluster/user.cpp | 8 ++++++++ src/dpp/cluster_coro_calls.cpp | 8 ++++++++ src/dpp/cluster_sync_calls.cpp | 8 ++++++++ 7 files changed, 106 insertions(+), 6 deletions(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 5264d83d30..2aa1e78129 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -3662,7 +3662,7 @@ class DPP_EXPORT cluster { /** * @brief Get all guild stickers - * @see https://discord.com/developers/docs/resources/sticker#get-guild-stickers + * @see https://discord.com/developers/docs/resources/sticker#list-guild-stickers * @param guild_id Guild ID of the guild where the sticker is * @param callback Function to call when the API call completes. * On success the callback will contain a dpp::sticker_map object in confirmation_callback_t::value. On failure, the value is undefined and confirmation_callback_t::is_error() method will return true. You can obtain full error details with confirmation_callback_t::get_error(). @@ -3671,7 +3671,7 @@ class DPP_EXPORT cluster { /** * @brief Get a list of available sticker packs - * @see https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs + * @see https://discord.com/developers/docs/resources/sticker#list-sticker-packs * @param callback Function to call when the API call completes. * On success the callback will contain a dpp::sticker_pack_map object in confirmation_callback_t::value. On failure, the value is undefined and confirmation_callback_t::is_error() method will return true. You can obtain full error details with confirmation_callback_t::get_error(). */ @@ -3821,6 +3821,16 @@ class DPP_EXPORT cluster { */ void current_user_set_voice_state(snowflake guild_id, snowflake channel_id, bool suppress = false, time_t request_to_speak_timestamp = 0, command_completion_event_t callback = utility::log_error()); + /** + * @brief Get the bot's voice state in a guild without a Gateway connection + * + * @see https://discord.com/developers/docs/resources/voice#get-current-user-voice-state + * @param guild_id Guild to get the voice state for + * @param callback Function to call when the API call completes. + * On success the callback will contain a dpp::voicestate object in confirmation_callback_t::value. On failure, the value is undefined and confirmation_callback_t::is_error() method will return true. You can obtain full error details with confirmation_callback_t::get_error(). + */ + void current_user_get_voice_state(snowflake guild_id, command_completion_event_t callback); + /** * @brief Set a user's voice state on a stage channel * @@ -3844,6 +3854,17 @@ class DPP_EXPORT cluster { */ void user_set_voice_state(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress = false, command_completion_event_t callback = utility::log_error()); + /** + * @brief Get a user's voice state in a guild without a Gateway connection + * + * @see https://discord.com/developers/docs/resources/voice#get-user-voice-state + * @param guild_id Guild to get the voice state for + * @param user_id The user to get the voice state of + * @param callback Function to call when the API call completes. + * On success the callback will contain a dpp::voicestate object in confirmation_callback_t::value. On failure, the value is undefined and confirmation_callback_t::is_error() method will return true. You can obtain full error details with confirmation_callback_t::get_error(). + */ + void user_get_voice_state(snowflake guild_id, snowflake user_id, command_completion_event_t callback); + /** * @brief Get all auto moderation rules for a guild * diff --git a/include/dpp/cluster_coro_calls.h b/include/dpp/cluster_coro_calls.h index 0ea93fc9b6..9077e9efa6 100644 --- a/include/dpp/cluster_coro_calls.h +++ b/include/dpp/cluster_coro_calls.h @@ -2009,7 +2009,7 @@ /** * @brief Get all guild stickers * @see dpp::cluster::guild_stickers_get - * @see https://discord.com/developers/docs/resources/sticker#get-guild-stickers + * @see https://discord.com/developers/docs/resources/sticker#list-guild-stickers * @param guild_id Guild ID of the guild where the sticker is * @return sticker_map returned object on completion * \memberof dpp::cluster @@ -2029,7 +2029,7 @@ /** * @brief Get a list of available sticker packs * @see dpp::cluster::sticker_packs_get - * @see https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs + * @see https://discord.com/developers/docs/resources/sticker#list-sticker-packs * @return sticker_pack_map returned object on completion * \memberof dpp::cluster */ @@ -2367,6 +2367,17 @@ */ [[nodiscard]] async co_current_user_set_voice_state(snowflake guild_id, snowflake channel_id, bool suppress = false, time_t request_to_speak_timestamp = 0); +/** + * @brief Get the bot's voice state in a guild without a Gateway connection + * + * @see dpp::cluster::current_user_get_voice_state + * @see https://discord.com/developers/docs/resources/voice#get-current-user-voice-state + * @param guild_id Guild to get the voice state for + * @return voicestate returned object on completion + * \memberof dpp::cluster + */ +[[nodiscard]] async co_current_user_get_voice_state(snowflake guild_id); + /** * @brief Set a user's voice state on a stage channel * @@ -2391,6 +2402,18 @@ */ [[nodiscard]] async co_user_set_voice_state(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress = false); +/** + * @brief Get a user's voice state in a guild without a Gateway connection + * + * @see dpp::cluster::user_get_voice_state + * @see https://discord.com/developers/docs/resources/voice#get-user-voice-state + * @param guild_id Guild to get the voice state for + * @param user_id The user to get the voice state of + * @return voicestate returned object on completion + * \memberof dpp::cluster + */ +[[nodiscard]] async co_user_get_voice_state(snowflake guild_id, snowflake user_id); + /** * @brief Get current user's connections (linked accounts, e.g. steam, xbox). * This call requires the oauth2 `connections` scope and cannot be executed diff --git a/include/dpp/cluster_sync_calls.h b/include/dpp/cluster_sync_calls.h index 74db0bff7c..86ccd5fc02 100644 --- a/include/dpp/cluster_sync_calls.h +++ b/include/dpp/cluster_sync_calls.h @@ -2621,7 +2621,7 @@ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev /** * @brief Get all guild stickers * @see dpp::cluster::guild_stickers_get - * @see https://discord.com/developers/docs/resources/sticker#get-guild-stickers + * @see https://discord.com/developers/docs/resources/sticker#list-guild-stickers * @param guild_id Guild ID of the guild where the sticker is * @return sticker_map returned object on completion * \memberof dpp::cluster @@ -2649,7 +2649,7 @@ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev /** * @brief Get a list of available sticker packs * @see dpp::cluster::sticker_packs_get - * @see https://discord.com/developers/docs/resources/sticker#list-nitro-sticker-packs + * @see https://discord.com/developers/docs/resources/sticker#list-sticker-packs * @return sticker_pack_map returned object on completion * \memberof dpp::cluster * @throw dpp::rest_exception upon failure to execute REST function @@ -3095,6 +3095,21 @@ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev */ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation current_user_set_voice_state_sync(snowflake guild_id, snowflake channel_id, bool suppress = false, time_t request_to_speak_timestamp = 0); +/** + * @brief Get the bot's voice state in a guild without a Gateway connection + * + * @see dpp::cluster::current_user_get_voice_state + * @see https://discord.com/developers/docs/resources/voice#get-current-user-voice-state + * @param guild_id Guild to get the voice state for + * @return voicestate returned object on completion + * \memberof dpp::cluster + * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. + * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. + * Avoid direct use of this function inside an event handler. + */ +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") voicestate current_user_get_voice_state_sync(snowflake guild_id); + /** * @brief Set a user's voice state on a stage channel * @@ -3123,6 +3138,22 @@ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev */ DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") confirmation user_set_voice_state_sync(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress = false); +/** + * @brief Get a user's voice state in a guild without a Gateway connection + * + * @see dpp::cluster::user_get_voice_state + * @see https://discord.com/developers/docs/resources/voice#get-user-voice-state + * @param guild_id Guild to get the voice state for + * @param user_id The user to get the voice state of + * @return voicestate returned object on completion + * \memberof dpp::cluster + * @throw dpp::rest_exception upon failure to execute REST function + * @deprecated This function is deprecated, please use coroutines instead. + * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread. + * Avoid direct use of this function inside an event handler. + */ +DPP_DEPRECATED("Please use coroutines instead of sync functions: https://dpp.dev/coro-introduction.html") voicestate user_get_voice_state_sync(snowflake guild_id, snowflake user_id); + /** * @brief Get current user's connections (linked accounts, e.g. steam, xbox). * This call requires the oauth2 `connections` scope and cannot be executed diff --git a/include/dpp/restresults.h b/include/dpp/restresults.h index 3dd0ebb69c..c496f13c79 100644 --- a/include/dpp/restresults.h +++ b/include/dpp/restresults.h @@ -156,6 +156,7 @@ typedef std::variant< ban_map, voiceregion, voiceregion_map, + voicestate, integration, integration_map, webhook, diff --git a/src/dpp/cluster/user.cpp b/src/dpp/cluster/user.cpp index 671fdb64a9..b3504ceae2 100644 --- a/src/dpp/cluster/user.cpp +++ b/src/dpp/cluster/user.cpp @@ -81,6 +81,10 @@ void cluster::current_user_set_voice_state(snowflake guild_id, snowflake channel rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/voice-states/@me", m_patch, j.dump(-1, ' ', false, json::error_handler_t::replace), callback); } +void cluster::current_user_get_voice_state(snowflake guild_id, command_completion_event_t callback) { + rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/voice-states/@me", m_get, "", callback); +} + void cluster::user_set_voice_state(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress, command_completion_event_t callback) { json j({ {"channel_id", channel_id}, @@ -89,6 +93,10 @@ void cluster::user_set_voice_state(snowflake user_id, snowflake guild_id, snowfl rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/voice-states/" + std::to_string(user_id), m_patch, j.dump(-1, ' ', false, json::error_handler_t::replace), callback); } +void cluster::user_get_voice_state(snowflake guild_id, snowflake user_id, command_completion_event_t callback) { + rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/voice-states/" + std::to_string(user_id), m_get, "", callback); +} + void cluster::current_user_connections_get(command_completion_event_t callback) { rest_request_list(this, API_PATH "/users", "@me", "connections", m_get, "", callback); } diff --git a/src/dpp/cluster_coro_calls.cpp b/src/dpp/cluster_coro_calls.cpp index d56b3b1013..3ec3aeff93 100644 --- a/src/dpp/cluster_coro_calls.cpp +++ b/src/dpp/cluster_coro_calls.cpp @@ -783,10 +783,18 @@ async cluster::co_current_user_set_voice_state(snowflak return async{ this, static_cast(&cluster::current_user_set_voice_state), guild_id, channel_id, suppress, request_to_speak_timestamp }; } +async cluster::co_current_user_get_voice_state(snowflake guild_id) { + return async{ this, static_cast(&cluster::current_user_get_voice_state), guild_id }; +} + async cluster::co_user_set_voice_state(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress) { return async{ this, static_cast(&cluster::user_set_voice_state), user_id, guild_id, channel_id, suppress }; } +async cluster::co_user_get_voice_state(snowflake guild_id, snowflake user_id) { + return async{ this, static_cast(&cluster::user_get_voice_state), guild_id, user_id }; +} + async cluster::co_current_user_connections_get() { return async{ this, static_cast(&cluster::current_user_connections_get) }; } diff --git a/src/dpp/cluster_sync_calls.cpp b/src/dpp/cluster_sync_calls.cpp index 8aa69aba77..c49c9d9a3e 100644 --- a/src/dpp/cluster_sync_calls.cpp +++ b/src/dpp/cluster_sync_calls.cpp @@ -781,10 +781,18 @@ confirmation cluster::current_user_set_voice_state_sync(snowflake guild_id, snow return dpp::sync(this, static_cast(&cluster::current_user_set_voice_state), guild_id, channel_id, suppress, request_to_speak_timestamp); } +voicestate cluster::current_user_get_voice_state_sync(snowflake guild_id) { + return dpp::sync(this, static_cast(&cluster::current_user_get_voice_state), guild_id); +} + confirmation cluster::user_set_voice_state_sync(snowflake user_id, snowflake guild_id, snowflake channel_id, bool suppress) { return dpp::sync(this, static_cast(&cluster::user_set_voice_state), user_id, guild_id, channel_id, suppress); } +voicestate cluster::user_get_voice_state_sync(snowflake guild_id, snowflake user_id) { + return dpp::sync(this, static_cast(&cluster::user_get_voice_state), guild_id, user_id); +} + connection_map cluster::current_user_connections_get_sync() { return dpp::sync(this, static_cast(&cluster::current_user_connections_get)); } From 3d24041f8e24ab5e25988a817f7f0e8d1e024d30 Mon Sep 17 00:00:00 2001 From: Neko Life Date: Sun, 20 Oct 2024 07:57:19 +0000 Subject: [PATCH 88/99] Feat/no user join ready dave (#1289) --- include/dpp/cluster.h | 11 -- include/dpp/discordvoiceclient.h | 37 +++++- include/dpp/dispatcher.h | 25 +--- src/dpp/discordvoiceclient.cpp | 27 +++- src/dpp/voice/enabled/courier_loop.cpp | 167 +++++++++++++++++++++---- src/dpp/voice/enabled/handle_frame.cpp | 5 + src/dpp/voice/enabled/opus.cpp | 8 +- src/dpp/voice/enabled/read_ready.cpp | 94 ++------------ src/dpp/voice/enabled/read_write.cpp | 17 +-- src/dpp/voice/enabled/write_ready.cpp | 11 +- src/dpp/voice/stub/stubs.cpp | 6 +- src/unittest/test.cpp | 1 - 12 files changed, 238 insertions(+), 171 deletions(-) diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 2aa1e78129..4825fe497f 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -1334,17 +1334,6 @@ class DPP_EXPORT cluster { event_router_t on_voice_buffer_send; - /** - * @brief Called when a user is talking on a voice channel. - * - * @warning If the cache policy has disabled guild caching, the pointer to the guild in this event may be nullptr. - * - * @note Use operator() to attach a lambda to this event, and the detach method to detach the listener using the returned ID. - * The function signature for this event takes a single `const` reference of type voice_user_talking_t&, and returns void. - */ - event_router_t on_voice_user_talking; - - /** * @brief Called when a voice channel is connected and ready to send audio. * Note that this is not directly attached to the READY event of the websocket, diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 658ba6422a..1330b7e0b2 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -240,6 +240,11 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ void cleanup(); + /** + * @brief A frame of silence packet + */ + static constexpr uint8_t silence_packet[3] = { 0xf8, 0xff, 0xfe }; + /** * @brief Mutex for outbound packet stream */ @@ -434,6 +439,13 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ bool paused; + /** + * @brief Whether has sent 5 frame of silence before stopping on pause. + * + * This is to avoid unintended Opus interpolation with subsequent transmissions. + */ + bool sent_stop_frames; + #ifdef HAVE_VOICE /** * @brief libopus encoder @@ -650,8 +662,10 @@ class DPP_EXPORT discord_voice_client : public websocket_client * @param packet packet data * @param len length of packet * @param duration duration of opus packet + * @param send_now send this packet right away without buffering. + * Do NOT set send_now to true outside write_ready. */ - void send(const char* packet, size_t len, uint64_t duration); + void send(const char* packet, size_t len, uint64_t duration, bool send_now = false); /** * @brief Queue a message to be sent via the websocket @@ -962,6 +976,10 @@ class DPP_EXPORT discord_voice_client : public websocket_client * @param duration Generally duration is 2.5, 5, 10, 20, 40 or 60 * if the timescale is 1000000 (1ms) * + * @param send_now Send this packet right away without buffering, + * this will skip duration calculation for the packet being sent + * and only safe to be set to true in write_ready. + * * @return discord_voice_client& Reference to self * * @note It is your responsibility to ensure that packets of data @@ -972,7 +990,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * * @throw dpp::voice_exception If data length is invalid or voice support not compiled into D++ */ - discord_voice_client& send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration); + discord_voice_client& send_audio_opus(const uint8_t* opus_packet, const size_t length, uint64_t duration, bool send_now = false); /** * @brief Send opus packets to the voice channel @@ -999,7 +1017,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client * * @throw dpp::voice_exception If data length is invalid or voice support not compiled into D++ */ - discord_voice_client& send_audio_opus(uint8_t* opus_packet, const size_t length); + discord_voice_client& send_audio_opus(const uint8_t* opus_packet, const size_t length); /** * @brief Send silence to the voice channel @@ -1012,6 +1030,19 @@ class DPP_EXPORT discord_voice_client : public websocket_client */ discord_voice_client& send_silence(const uint64_t duration); + /** + * @brief Send stop frames to the voice channel. + * + * @param send_now send this packet right away without buffering. + * Do NOT set send_now to true outside write_ready. + * Also make sure you're not locking stream_mutex if you + * don't set send_now to true. + * + * @return discord_voice_client& Reference to self + * @throw dpp::voice_exception if voice support is not compiled into D++ + */ + discord_voice_client& send_stop_frames(bool send_now = false); + /** * @brief Sets the audio type that will be sent with send_audio_* methods. * diff --git a/include/dpp/dispatcher.h b/include/dpp/dispatcher.h index 151c2e8880..749f3a0454 100644 --- a/include/dpp/dispatcher.h +++ b/include/dpp/dispatcher.h @@ -1989,30 +1989,7 @@ struct DPP_EXPORT voice_buffer_send_t : public event_dispatch_t { }; /** - * @brief voice user talking - */ -struct DPP_EXPORT voice_user_talking_t : public event_dispatch_t { - using event_dispatch_t::event_dispatch_t; - using event_dispatch_t::operator=; - - /** - * @brief voice client where user is talking - */ - class discord_voice_client* voice_client = nullptr; - - /** - * @brief talking user id - */ - snowflake user_id = {}; - - /** - * @brief flags for talking user - */ - uint8_t talking_flags = 0; -}; - -/** - * @brief voice user talking + * @brief voice ready */ struct DPP_EXPORT voice_ready_t : public event_dispatch_t { using event_dispatch_t::event_dispatch_t; diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 1b8fe7b95f..4a4f484968 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -20,6 +20,7 @@ * ************************************************************************************/ +#include #ifdef _WIN32 #include #include @@ -148,6 +149,9 @@ bool discord_voice_client::is_end_to_end_encrypted() const { discord_voice_client& discord_voice_client::pause_audio(bool pause) { this->paused = pause; + if (!this->paused) { + this->sent_stop_frames = false; + } return *this; } @@ -172,10 +176,13 @@ dpp::utility::uptime discord_voice_client::get_remaining() { } discord_voice_client& discord_voice_client::stop_audio() { - std::lock_guard lock(this->stream_mutex); - outbuf.clear(); - track_meta.clear(); - tracks = 0; + { + std::lock_guard lock(this->stream_mutex); + outbuf.clear(); + track_meta.clear(); + tracks = 0; + } + this->send_stop_frames(); return *this; } @@ -398,7 +405,6 @@ discord_voice_client& discord_voice_client::skip_to_next_marker() { } discord_voice_client& discord_voice_client::send_silence(const uint64_t duration) { - uint8_t silence_packet[3] = { 0xf8, 0xff, 0xfe }; send_audio_opus(silence_packet, 3, duration); return *this; } @@ -443,4 +449,15 @@ uint16_t discord_voice_client::get_iteration_interval() { return this->iteration_interval; } +discord_voice_client& discord_voice_client::send_stop_frames(bool send_now) { + uint8_t silence_frames[sizeof(silence_packet) / sizeof(*silence_packet) * 5]; + for (size_t i = 0; i < sizeof(silence_frames) / sizeof(*silence_frames); i++) { + silence_frames[i] = silence_packet[i % 3]; + } + + this->send_audio_opus(silence_frames, sizeof(silence_frames) / sizeof(*silence_frames), 20, send_now); + + return *this; +} + } // namespace dpp diff --git a/src/dpp/voice/enabled/courier_loop.cpp b/src/dpp/voice/enabled/courier_loop.cpp index 6526c7f8ba..72ccccdbfc 100644 --- a/src/dpp/voice/enabled/courier_loop.cpp +++ b/src/dpp/voice/enabled/courier_loop.cpp @@ -21,6 +21,7 @@ ************************************************************************************/ #include +#include #include #include #include @@ -34,6 +35,7 @@ namespace dpp { void discord_voice_client::voice_courier_loop(discord_voice_client& client, courier_shared_state_t& shared_state) { utility::set_thread_name(std::string("vcourier/") + std::to_string(client.server_id)); + while (true) { std::this_thread::sleep_for(std::chrono::milliseconds{client.iteration_interval}); @@ -59,13 +61,17 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour bool has_payload_to_deliver = false; for (auto &[user_id, parking_lot]: shared_state.parked_voice_payloads) { has_payload_to_deliver = has_payload_to_deliver || !parking_lot.parked_payloads.empty(); - flush_data.push_back(flush_data_t{user_id, - parking_lot.range.min_seq, - std::move(parking_lot.parked_payloads), + + flush_data.push_back(flush_data_t{ + user_id, + parking_lot.range.min_seq, + std::move(parking_lot.parked_payloads), /* Quickly check if we already have a decoder and only take the pending ctls if so. */ - parking_lot.decoder ? std::move(parking_lot.pending_decoder_ctls) - : decltype(parking_lot.pending_decoder_ctls){}, - parking_lot.decoder}); + parking_lot.decoder ? std::move(parking_lot.pending_decoder_ctls) + : decltype(parking_lot.pending_decoder_ctls){}, + parking_lot.decoder + }); + parking_lot.range.min_seq = parking_lot.range.max_seq + 1; parking_lot.range.min_timestamp = parking_lot.range.max_timestamp + 1; } @@ -76,7 +82,24 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour break; } - shared_state.signal_iteration.wait(lk); + shared_state.signal_iteration.wait(lk, [&shared_state](){ + if (shared_state.terminating) { + return true; + } + + /* + * Actually check the state we're looking for instead of waking up + * everytime read_ready was called. + */ + for (auto &[user_id, parking_lot]: shared_state.parked_voice_payloads) { + if (parking_lot.parked_payloads.empty()) { + continue; + } + return true; + } + return false; + }); + /* * More data came or about to terminate, or just a spurious wake. * We need to collect the payloads again to determine what to do next. @@ -95,13 +118,14 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour /* This 32 bit PCM audio buffer is an upmixed version of the streams * combined for all users. This is a wider width audio buffer so that - * there is no clipping when there are many loud audio sources at once. + * there is no clipping when there are many loud audio sources at once. */ opus_int32 pcm_mix[23040] = {0}; size_t park_count = 0; int max_samples = 0; int samples = 0; + opus_int16 flush_data_pcm[23040]; for (auto &d: flush_data) { if (!d.decoder) { continue; @@ -109,37 +133,133 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour for (const auto &decoder_ctl: d.pending_decoder_ctls) { decoder_ctl(*d.decoder); } + for (rtp_seq_t seq = d.min_seq; !d.parked_payloads.empty(); ++seq) { - opus_int16 pcm[23040]; if (d.parked_payloads.top().seq != seq) { /* * Lost a packet with sequence number "seq", * But Opus decoder might be able to guess something. */ - if (int samples = opus_decode(d.decoder.get(), nullptr, 0, pcm, 5760, 0); - samples >= 0) { + if (int lost_packet_samples = opus_decode(d.decoder.get(), nullptr, 0, flush_data_pcm, 5760, 0); + lost_packet_samples >= 0) { /* * Since this sample comes from a lost packet, * we can only pretend there is an event, without any raw payload byte. */ - voice_receive_t vr(nullptr, "", &client, d.user_id, reinterpret_cast(pcm), - samples * opus_channel_count * sizeof(opus_int16)); + voice_receive_t vr(nullptr, "", &client, d.user_id, + reinterpret_cast(flush_data_pcm), + lost_packet_samples * opus_channel_count * sizeof(opus_int16)); - park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); + park_count = audio_mix(client, *client.mixer, pcm_mix, flush_data_pcm, park_count, lost_packet_samples, max_samples); client.creator->on_voice_receive.call(vr); } } else { voice_receive_t &vr = *d.parked_payloads.top().vr; - if (vr.audio_data.size() > 0x7FFFFFFF) { + + /* + * We do decryption here to avoid blocking ssl_client and saving cpu time by doing it when needed only. + * + * NOTE: You do not want to send audio while also listening for on_voice_receive/on_voice_receive_combined. + * It will cause gaps in your recording, I have no idea why exactly. + */ + + constexpr size_t header_size = 12; + + uint8_t *buffer = vr.audio_data.data(); + size_t packet_size = vr.audio_data.size(); + + constexpr size_t nonce_size = sizeof(uint32_t); + /* Nonce is 4 byte at the end of payload with zero padding */ + uint8_t nonce[24] = { 0 }; + std::memcpy(nonce, buffer + packet_size - nonce_size, nonce_size); + + /* Get the number of CSRC in header */ + const size_t csrc_count = buffer[0] & 0b0000'1111; + /* Skip to the encrypted voice data */ + const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; + size_t total_header_len = offset_to_data; + + uint8_t* ciphertext = buffer + offset_to_data; + size_t ciphertext_len = packet_size - offset_to_data - nonce_size; + + size_t ext_len = 0; + if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { + /** + * Get the RTP Extensions size, we only get the size here because + * the extension itself is encrypted along with the opus packet + */ + { + uint16_t ext_len_in_words; + memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); + ext_len_in_words = ntohs(ext_len_in_words); + ext_len = sizeof(uint32_t) * ext_len_in_words; + } + constexpr size_t ext_header_len = sizeof(uint16_t) * 2; + ciphertext += ext_header_len; + ciphertext_len -= ext_header_len; + total_header_len += ext_header_len; + } + + uint8_t decrypted[65535] = { 0 }; + unsigned long long opus_packet_len = 0; + if (ssl_crypto_aead_xchacha20poly1305_ietf_decrypt( + decrypted, &opus_packet_len, + nullptr, + ciphertext, ciphertext_len, + buffer, + /** + * Additional Data: + * The whole header (including csrc list) + + * 4 byte extension header (magic 0xBEDE + 16-bit denoting extension length) + */ + total_header_len, + nonce, vr.voice_client->secret_key.data()) != 0) { + /* Invalid Discord RTP payload. */ + return; + } + + uint8_t *opus_packet = decrypted; + if (ext_len > 0) { + /* Skip previously encrypted RTP Header Extension */ + opus_packet += ext_len; + opus_packet_len -= ext_len; + } + + /** + * If DAVE is enabled, use the user's ratchet to decrypt the OPUS audio data + */ + std::vector decrypted_dave_frame; + if (vr.voice_client->is_end_to_end_encrypted()) { + auto decryptor = vr.voice_client->mls_state->decryptors.find(vr.user_id); + + if (decryptor != vr.voice_client->mls_state->decryptors.end()) { + decrypted_dave_frame.resize(decryptor->second->get_max_plaintext_byte_size(dave::media_type::media_audio, opus_packet_len)); + + size_t enc_len = decryptor->second->decrypt( + dave::media_type::media_audio, + dave::make_array_view(opus_packet, opus_packet_len), + dave::make_array_view(decrypted_dave_frame) + ); + + if (enc_len > 0) { + opus_packet = decrypted_dave_frame.data(); + opus_packet_len = enc_len; + } + } + } + + if (opus_packet_len > 0x7FFFFFFF) { throw dpp::length_exception(err_massive_audio, "audio_data > 2GB! This should never happen!"); } - if (samples = opus_decode(d.decoder.get(), vr.audio_data.data(), - static_cast(vr.audio_data.size() & 0x7FFFFFFF), pcm, 5760, 0); - samples >= 0) { - vr.reassign(&client, d.user_id, reinterpret_cast(pcm), - samples * opus_channel_count * sizeof(opus_int16)); + + samples = opus_decode(d.decoder.get(), opus_packet, static_cast(opus_packet_len & 0x7FFFFFFF), flush_data_pcm, 5760, 0); + + if (samples >= 0) { + vr.reassign(&client, d.user_id, reinterpret_cast(flush_data_pcm), samples * opus_channel_count * sizeof(opus_int16)); + client.end_gain = 1.0f / client.moving_average; - park_count = audio_mix(client, *client.mixer, pcm_mix, pcm, park_count, samples, max_samples); + park_count = audio_mix(client, *client.mixer, pcm_mix, flush_data_pcm, park_count, samples, max_samples); + client.creator->on_voice_receive.call(vr); } @@ -147,15 +267,14 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour } } } - /* If combined receive is bound, dispatch it */ if (park_count) { - /* Downsample the 32 bit samples back to 16 bit */ opus_int16 pcm_downsample[23040] = {0}; opus_int16 *pcm_downsample_ptr = pcm_downsample; opus_int32 *pcm_mix_ptr = pcm_mix; client.increment = (client.end_gain - client.current_gain) / static_cast(samples); + for (int64_t x = 0; x < (samples * opus_channel_count) / client.mixer->byte_blocks_per_register; ++x) { client.mixer->collect_single_register(pcm_mix_ptr, pcm_downsample_ptr, client.current_gain, client.increment); client.current_gain += client.increment * static_cast(client.mixer->byte_blocks_per_register); @@ -164,7 +283,7 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour } voice_receive_t vr(nullptr, "", &client, 0, reinterpret_cast(pcm_downsample), - max_samples * opus_channel_count * sizeof(opus_int16)); + max_samples * opus_channel_count * sizeof(opus_int16)); client.creator->on_voice_receive_combined.call(vr); } diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp index 07423d3377..0b84cc1ca4 100644 --- a/src/dpp/voice/enabled/handle_frame.cpp +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -411,6 +411,11 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod }); } this->reinit_dave_mls_group(); + + /* Ready now if there's no DAVE user waiting in the vc */ + if (dave_mls_user_list.empty()) { + ready_now = true; + } } } else { /* Non-DAVE ready immediately */ diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp index d99a3776d0..a92886ac9c 100644 --- a/src/dpp/voice/enabled/opus.cpp +++ b/src/dpp/voice/enabled/opus.cpp @@ -71,14 +71,14 @@ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, return *this; } -discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length) { +discord_voice_client& discord_voice_client::send_audio_opus(const uint8_t* opus_packet, const size_t length) { int samples = opus_packet_get_nb_samples(opus_packet, (opus_int32)length, opus_sample_rate_hz); uint64_t duration = (samples / 48) / (timescale / 1000000); - send_audio_opus(opus_packet, length, duration); + send_audio_opus(opus_packet, length, duration, false); return *this; } -discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { +discord_voice_client& discord_voice_client::send_audio_opus(const uint8_t* opus_packet, const size_t length, uint64_t duration, bool send_now) { int frame_size = (int)(48 * duration * (timescale / 1000000)); opus_int32 encoded_audio_max_length = (opus_int32)length; std::vector encoded_audio(encoded_audio_max_length); @@ -147,7 +147,7 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet /* Append the 4 byte nonce to the resulting payload */ std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); - this->send(reinterpret_cast(payload.data()), payload.size(), duration); + this->send(reinterpret_cast(payload.data()), payload.size(), duration, send_now); timestamp += frame_size; diff --git a/src/dpp/voice/enabled/read_ready.cpp b/src/dpp/voice/enabled/read_ready.cpp index 95ac598160..03c79b0486 100644 --- a/src/dpp/voice/enabled/read_ready.cpp +++ b/src/dpp/voice/enabled/read_ready.cpp @@ -20,6 +20,7 @@ * ************************************************************************************/ +#include #include #include #include @@ -66,8 +67,8 @@ void discord_voice_client::read_ready() } voice_payload vp{0, // seq, populate later - 0, // timestamp, populate later - std::make_unique(nullptr, std::string(reinterpret_cast(buffer), packet_size))}; + 0, // timestamp, populate later + std::make_unique(nullptr, std::string(reinterpret_cast(buffer), packet_size))}; vp.vr->voice_client = this; @@ -86,88 +87,7 @@ void discord_voice_client::read_ready() std::memcpy(&vp.timestamp, &buffer[4], sizeof(rtp_timestamp_t)); vp.timestamp = ntohl(vp.timestamp); - constexpr size_t nonce_size = sizeof(uint32_t); - /* Nonce is 4 byte at the end of payload with zero padding */ - uint8_t nonce[24] = { 0 }; - std::memcpy(nonce, buffer + packet_size - nonce_size, nonce_size); - - /* Get the number of CSRC in header */ - const size_t csrc_count = buffer[0] & 0b0000'1111; - /* Skip to the encrypted voice data */ - const ptrdiff_t offset_to_data = header_size + sizeof(uint32_t) * csrc_count; - size_t total_header_len = offset_to_data; - - uint8_t* ciphertext = buffer + offset_to_data; - size_t ciphertext_len = packet_size - offset_to_data - nonce_size; - - size_t ext_len = 0; - if ([[maybe_unused]] const bool uses_extension = (buffer[0] >> 4) & 0b0001) { - /** - * Get the RTP Extensions size, we only get the size here because - * the extension itself is encrypted along with the opus packet - */ - { - uint16_t ext_len_in_words; - memcpy(&ext_len_in_words, &ciphertext[2], sizeof(uint16_t)); - ext_len_in_words = ntohs(ext_len_in_words); - ext_len = sizeof(uint32_t) * ext_len_in_words; - } - constexpr size_t ext_header_len = sizeof(uint16_t) * 2; - ciphertext += ext_header_len; - ciphertext_len -= ext_header_len; - total_header_len += ext_header_len; - } - - uint8_t decrypted[65535] = { 0 }; - unsigned long long opus_packet_len = 0; - if (ssl_crypto_aead_xchacha20poly1305_ietf_decrypt( - decrypted, &opus_packet_len, - nullptr, - ciphertext, ciphertext_len, - buffer, - /** - * Additional Data: - * The whole header (including csrc list) + - * 4 byte extension header (magic 0xBEDE + 16-bit denoting extension length) - */ - total_header_len, - nonce, secret_key.data()) != 0) { - /* Invalid Discord RTP payload. */ - return; - } - - uint8_t *opus_packet = decrypted; - if (ext_len > 0) { - /* Skip previously encrypted RTP Header Extension */ - opus_packet += ext_len; - opus_packet_len -= ext_len; - } - - /** - * If DAVE is enabled, use the user's ratchet to decrypt the OPUS audio data - */ - std::vector frame; - if (is_end_to_end_encrypted()) { - auto decryptor = mls_state->decryptors.find(vp.vr->user_id); - if (decryptor != mls_state->decryptors.end()) { - frame.resize(decryptor->second->get_max_plaintext_byte_size(dave::media_type::media_audio, opus_packet_len)); - size_t enc_len = decryptor->second->decrypt( - dave::media_type::media_audio, - dave::make_array_view(opus_packet, opus_packet_len), - dave::make_array_view(frame) - ); - if (enc_len > 0) { - opus_packet = frame.data(); - opus_packet_len = enc_len; - } - } - } - - /* - * We're left with the decrypted, opus-encoded data. - * Park the payload and decode on the voice courier thread. - */ - vp.vr->audio_data.assign(opus_packet, opus_packet + opus_packet_len); + vp.vr->audio_data.assign(buffer, buffer + packet_size); { std::lock_guard lk(voice_courier_shared_state.mtx); @@ -183,7 +103,7 @@ void discord_voice_client::read_ready() int opus_error = 0; decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), - &opus_decoder_destroy); + &opus_decoder_destroy); if (opus_error) { /** * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, @@ -207,8 +127,8 @@ void discord_voice_client::read_ready() if (!voice_courier.joinable()) { /* Courier thread is not running, start it */ voice_courier = std::thread(&voice_courier_loop, - std::ref(*this), - std::ref(voice_courier_shared_state)); + std::ref(*this), + std::ref(voice_courier_shared_state)); } } diff --git a/src/dpp/voice/enabled/read_write.cpp b/src/dpp/voice/enabled/read_write.cpp index c24200b49b..52a09d5a39 100644 --- a/src/dpp/voice/enabled/read_write.cpp +++ b/src/dpp/voice/enabled/read_write.cpp @@ -30,7 +30,7 @@ namespace dpp { dpp::socket discord_voice_client::want_write() { std::lock_guard lock(this->stream_mutex); - if (!this->paused && !outbuf.empty()) { + if (!this->sent_stop_frames && !outbuf.empty()) { return fd; } return INVALID_SOCKET; @@ -42,13 +42,16 @@ dpp::socket discord_voice_client::want_read() { } -void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { - voice_out_packet frame; - frame.packet.assign(packet, packet + len); - frame.duration = duration; - { +void discord_voice_client::send(const char* packet, size_t len, uint64_t duration, bool send_now) { + if (!send_now) [[likely]] { + voice_out_packet frame; + frame.packet.assign(packet, packet + len); + frame.duration = duration; + std::lock_guard lock(this->stream_mutex); outbuf.emplace_back(frame); + } else [[unlikely]] { + this->udp_send(packet, len); } } @@ -68,4 +71,4 @@ int discord_voice_client::udp_recv(char* data, size_t max_length) return static_cast(recv(this->fd, data, static_cast(max_length), 0)); } -} \ No newline at end of file +} diff --git a/src/dpp/voice/enabled/write_ready.cpp b/src/dpp/voice/enabled/write_ready.cpp index 46c0307055..8287dea2a3 100644 --- a/src/dpp/voice/enabled/write_ready.cpp +++ b/src/dpp/voice/enabled/write_ready.cpp @@ -37,7 +37,14 @@ void discord_voice_client::write_ready() { send_audio_type_t type = satype_recorded_audio; { std::lock_guard lock(this->stream_mutex); - if (!this->paused && outbuf.size()) { + if (this->paused) { + if (!this->sent_stop_frames) { + this->send_stop_frames(true); + this->sent_stop_frames = true; + } + + /* Fallthrough if paused */ + } else if (!outbuf.empty()) { type = send_audio_type; if (outbuf[0].packet.size() == sizeof(uint16_t) && (*(reinterpret_cast(outbuf[0].packet.data()))) == AUDIO_TRACK_MARKER) { outbuf.erase(outbuf.begin()); @@ -46,7 +53,7 @@ void discord_voice_client::write_ready() { tracks--; } } - if (outbuf.size()) { + if (!outbuf.empty()) { if (this->udp_send(outbuf[0].packet.data(), outbuf[0].packet.length()) == (int)outbuf[0].packet.length()) { duration = outbuf[0].duration * timescale; bufsize = outbuf[0].packet.length(); diff --git a/src/dpp/voice/stub/stubs.cpp b/src/dpp/voice/stub/stubs.cpp index b184367d98..c027aa8b43 100644 --- a/src/dpp/voice/stub/stubs.cpp +++ b/src/dpp/voice/stub/stubs.cpp @@ -63,11 +63,11 @@ namespace dpp { return *this; } - discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length) { + discord_voice_client& discord_voice_client::send_audio_opus(const uint8_t* opus_packet, const size_t length, uint64_t duration, bool send_now) { return *this; } - discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet, const size_t length, uint64_t duration) { + discord_voice_client& discord_voice_client::send_audio_opus(const uint8_t* opus_packet, const size_t length) { return *this; } @@ -80,7 +80,7 @@ namespace dpp { } - void discord_voice_client::send(const char* packet, size_t len, uint64_t duration) { + void discord_voice_client::send(const char* packet, size_t len, uint64_t duration, bool send_now) { } int discord_voice_client::udp_send(const char* data, size_t length) { diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 7c61570ab7..da96a28096 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -641,7 +641,6 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::thread_member_update_t, success); DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::thread_members_update_t, success); DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::voice_buffer_send_t, success); - DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::voice_user_talking_t, success); DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::voice_ready_t, success); DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::voice_receive_t, success); DPP_CHECK_CONSTRUCT_ASSIGN(EVENT_CLASS, dpp::voice_client_speaking_t, success); From 8f26e784713fe6efa8279eadfbc38c5756a4ad77 Mon Sep 17 00:00:00 2001 From: "Craig Edwards (Brain)" Date: Sun, 20 Oct 2024 11:35:48 +0100 Subject: [PATCH 89/99] refactor: cleanup namespaces and unneeded includes (#1295) --- include/dpp/appcommand.h | 2 +- include/dpp/application.h | 2 +- include/dpp/auditlog.h | 2 +- include/dpp/automod.h | 2 +- include/dpp/ban.h | 2 +- include/dpp/bignum.h | 2 +- include/dpp/cache.h | 2 +- include/dpp/channel.h | 2 +- include/dpp/cluster.h | 2 +- include/dpp/collector.h | 2 +- include/dpp/commandhandler.h | 2 +- include/dpp/coro/async.h | 2 +- include/dpp/coro/coroutine.h | 2 +- include/dpp/coro/task.h | 2 +- include/dpp/discordclient.h | 2 +- include/dpp/discordevents.h | 2 +- include/dpp/discordvoiceclient.h | 2 +- include/dpp/dispatcher.h | 2 +- include/dpp/dtemplate.h | 2 +- include/dpp/emoji.h | 2 +- include/dpp/entitlement.h | 2 +- include/dpp/etf.h | 2 +- include/dpp/event.h | 2 +- include/dpp/event_router.h | 2 +- include/dpp/exception.h | 2 +- include/dpp/guild.h | 2 +- include/dpp/httpsclient.h | 2 +- include/dpp/integration.h | 2 +- include/dpp/intents.h | 2 +- include/dpp/invite.h | 2 +- include/dpp/isa/avx.h | 2 +- include/dpp/isa/avx2.h | 2 +- include/dpp/isa/avx512.h | 2 +- include/dpp/isa/fallback.h | 2 +- include/dpp/json_interface.h | 2 +- include/dpp/managed.h | 2 +- include/dpp/message.h | 2 +- include/dpp/misc-enum.h | 2 +- include/dpp/once.h | 2 +- include/dpp/permissions.h | 2 +- include/dpp/presence.h | 2 +- include/dpp/prune.h | 2 +- include/dpp/queues.h | 2 +- include/dpp/restrequest.h | 2 +- include/dpp/restresults.h | 2 +- include/dpp/role.h | 2 +- include/dpp/sku.h | 2 +- include/dpp/snowflake.h | 2 +- include/dpp/sslclient.h | 2 +- include/dpp/stage_instance.h | 2 +- include/dpp/stringops.h | 2 +- include/dpp/sync.h | 2 +- include/dpp/timed_listener.h | 2 +- include/dpp/timer.h | 2 +- include/dpp/user.h | 2 +- include/dpp/utility.h | 2 +- include/dpp/voiceregion.h | 2 +- include/dpp/voicestate.h | 2 +- include/dpp/webhook.h | 2 +- include/dpp/wsclient.h | 2 +- src/dpp/application.cpp | 6 +----- src/dpp/auditlog.cpp | 2 +- src/dpp/automod.cpp | 2 +- src/dpp/ban.cpp | 2 +- src/dpp/cache.cpp | 4 +--- src/dpp/channel.cpp | 3 +-- src/dpp/cluster.cpp | 8 ------- src/dpp/cluster/appcommand.cpp | 2 +- src/dpp/cluster/automod.cpp | 2 +- src/dpp/cluster/channel.cpp | 2 +- src/dpp/cluster/confirmation.cpp | 2 +- src/dpp/cluster/dm.cpp | 2 +- src/dpp/cluster/emoji.cpp | 2 +- src/dpp/cluster/entitlement.cpp | 2 +- src/dpp/cluster/gateway.cpp | 2 +- src/dpp/cluster/guild.cpp | 2 +- src/dpp/cluster/guild_member.cpp | 2 +- src/dpp/cluster/invite.cpp | 2 +- src/dpp/cluster/json_interface.cpp | 2 +- src/dpp/cluster/message.cpp | 2 +- src/dpp/cluster/role.cpp | 2 +- src/dpp/cluster/scheduled_event.cpp | 2 +- src/dpp/cluster/sku.cpp | 2 +- src/dpp/cluster/stage_instance.cpp | 2 +- src/dpp/cluster/sticker.cpp | 2 +- src/dpp/cluster/template.cpp | 2 +- src/dpp/cluster/thread.cpp | 2 +- src/dpp/cluster/timer.cpp | 2 +- src/dpp/cluster/user.cpp | 2 +- src/dpp/cluster/voice.cpp | 2 +- src/dpp/cluster/webhook.cpp | 2 +- src/dpp/commandhandler.cpp | 3 +-- src/dpp/discordclient.cpp | 15 +------------ src/dpp/discordevents.cpp | 8 ++----- src/dpp/discordvoiceclient.cpp | 12 +---------- src/dpp/dispatcher.cpp | 2 +- src/dpp/dns.cpp | 1 - src/dpp/dtemplate.cpp | 2 +- src/dpp/emoji.cpp | 3 +-- src/dpp/entitlement.cpp | 2 +- src/dpp/etf.cpp | 4 +--- src/dpp/guild.cpp | 5 +---- src/dpp/httpsclient.cpp | 4 +--- src/dpp/integration.cpp | 4 +--- src/dpp/invite.cpp | 4 +--- src/dpp/message.cpp | 2 +- src/dpp/permissions.cpp | 2 +- src/dpp/presence.cpp | 14 +++++------- src/dpp/prune.cpp | 2 +- src/dpp/queues.cpp | 3 +-- src/dpp/role.cpp | 6 +----- src/dpp/scheduled_event.cpp | 3 +-- src/dpp/sku.cpp | 2 +- src/dpp/slashcommand.cpp | 3 +-- src/dpp/snowflake.cpp | 2 +- src/dpp/sslclient.cpp | 13 +++--------- src/dpp/stage_instance.cpp | 2 +- src/dpp/thread.cpp | 1 - src/dpp/user.cpp | 33 ++++++++++++----------------- src/dpp/utility.cpp | 6 +----- src/dpp/voice/enabled/audio_mix.cpp | 2 -- src/dpp/voice/enabled/cleanup.cpp | 2 -- src/dpp/voiceregion.cpp | 3 +-- src/dpp/voicestate.cpp | 3 +-- src/dpp/webhook.cpp | 4 +--- src/dpp/wsclient.cpp | 2 +- 126 files changed, 141 insertions(+), 233 deletions(-) diff --git a/include/dpp/appcommand.h b/include/dpp/appcommand.h index e628bd97f8..a4f99f7938 100644 --- a/include/dpp/appcommand.h +++ b/include/dpp/appcommand.h @@ -1591,4 +1591,4 @@ typedef std::unordered_map slashcommand_map; */ typedef std::unordered_map guild_command_permissions_map; -} // namespace dpp +} diff --git a/include/dpp/application.h b/include/dpp/application.h index f49dd9735a..5fae5738d5 100644 --- a/include/dpp/application.h +++ b/include/dpp/application.h @@ -472,4 +472,4 @@ class DPP_EXPORT application : public managed, public json_interface application_map; -} // namespace dpp +} diff --git a/include/dpp/auditlog.h b/include/dpp/auditlog.h index 90339ec331..5af57abdb7 100644 --- a/include/dpp/auditlog.h +++ b/include/dpp/auditlog.h @@ -478,4 +478,4 @@ class DPP_EXPORT auditlog : public json_interface { virtual ~auditlog() = default; }; -} // namespace dpp +} diff --git a/include/dpp/automod.h b/include/dpp/automod.h index f01c81d821..05c194f47f 100644 --- a/include/dpp/automod.h +++ b/include/dpp/automod.h @@ -400,4 +400,4 @@ class DPP_EXPORT automod_rule : public managed, public json_interface automod_rule_map; -} // namespace dpp +} diff --git a/include/dpp/ban.h b/include/dpp/ban.h index 6a02352ed1..039aa90e31 100644 --- a/include/dpp/ban.h +++ b/include/dpp/ban.h @@ -66,4 +66,4 @@ class DPP_EXPORT ban : public json_interface { */ typedef std::unordered_map ban_map; -} // namespace dpp +} diff --git a/include/dpp/bignum.h b/include/dpp/bignum.h index 2966d7b8b0..6d13f8f472 100644 --- a/include/dpp/bignum.h +++ b/include/dpp/bignum.h @@ -98,4 +98,4 @@ class DPP_EXPORT bignumber { [[nodiscard]] std::vector get_binary() const; }; -} // namespace dpp +} diff --git a/include/dpp/cache.h b/include/dpp/cache.h index cdfa3788f8..f4bb884e98 100644 --- a/include/dpp/cache.h +++ b/include/dpp/cache.h @@ -270,5 +270,5 @@ cache_decl(role, find_role, get_role_cache, get_role_count); cache_decl(channel, find_channel, get_channel_cache, get_channel_count); cache_decl(emoji, find_emoji, get_emoji_cache, get_emoji_count); -} // namespace dpp +} diff --git a/include/dpp/channel.h b/include/dpp/channel.h index 6b97b9e23a..4550bfc247 100644 --- a/include/dpp/channel.h +++ b/include/dpp/channel.h @@ -878,5 +878,5 @@ void to_json(nlohmann::json& j, const permission_overwrite& po); */ typedef std::unordered_map channel_map; -} // namespace dpp +} diff --git a/include/dpp/cluster.h b/include/dpp/cluster.h index 4825fe497f..9c283e4a72 100644 --- a/include/dpp/cluster.h +++ b/include/dpp/cluster.h @@ -3982,4 +3982,4 @@ class DPP_EXPORT cluster { }; -} // namespace dpp +} diff --git a/include/dpp/collector.h b/include/dpp/collector.h index ac09bf95a6..7d25c1e659 100644 --- a/include/dpp/collector.h +++ b/include/dpp/collector.h @@ -470,4 +470,4 @@ class scheduled_event_collector : public scheduled_event_collector_t { virtual ~scheduled_event_collector() = default; }; -} // namespace dpp +} diff --git a/include/dpp/commandhandler.h b/include/dpp/commandhandler.h index 1958bc43d4..c8be5c9c97 100644 --- a/include/dpp/commandhandler.h +++ b/include/dpp/commandhandler.h @@ -425,4 +425,4 @@ class DPP_EXPORT DPP_DEPRECATED("commandhandler should not be used. Please consi }; -} // namespace dpp +} diff --git a/include/dpp/coro/async.h b/include/dpp/coro/async.h index 4295ae1218..2feac38d8a 100644 --- a/include/dpp/coro/async.h +++ b/include/dpp/coro/async.h @@ -184,6 +184,6 @@ class async : public awaitable { DPP_CHECK_ABI_COMPAT(async<>, async_dummy); -} // namespace dpp +} #endif /* DPP_CORO */ diff --git a/include/dpp/coro/coroutine.h b/include/dpp/coro/coroutine.h index a9e7a5d100..648ac2b79b 100644 --- a/include/dpp/coro/coroutine.h +++ b/include/dpp/coro/coroutine.h @@ -393,7 +393,7 @@ namespace detail::coroutine { DPP_CHECK_ABI_COMPAT(coroutine, coroutine_dummy) DPP_CHECK_ABI_COMPAT(coroutine, coroutine_dummy) -} // namespace dpp +} /** * @brief Specialization of std::coroutine_traits, helps the standard library figure out a promise type from a coroutine function. diff --git a/include/dpp/coro/task.h b/include/dpp/coro/task.h index 6625bb1f3e..d57bc8ce7f 100644 --- a/include/dpp/coro/task.h +++ b/include/dpp/coro/task.h @@ -433,7 +433,7 @@ std_coroutine::coroutine_handle<> final_awaiter::await_suspend(handle_t ha DPP_CHECK_ABI_COMPAT(task, task_dummy) DPP_CHECK_ABI_COMPAT(task, task_dummy) -} // namespace dpp +} /** * @brief Specialization of std::coroutine_traits, helps the standard library figure out a promise_t type from a coroutine function. diff --git a/include/dpp/discordclient.h b/include/dpp/discordclient.h index 872dbaa916..d57c2d775b 100644 --- a/include/dpp/discordclient.h +++ b/include/dpp/discordclient.h @@ -533,4 +533,4 @@ class DPP_EXPORT discord_client : public websocket_client voiceconn* get_voice(snowflake guild_id); }; -} // namespace dpp +} diff --git a/include/dpp/discordevents.h b/include/dpp/discordevents.h index 184294818b..c603239b61 100644 --- a/include/dpp/discordevents.h +++ b/include/dpp/discordevents.h @@ -229,4 +229,4 @@ std::string DPP_EXPORT base64_encode(unsigned char const* buf, unsigned int buff */ std::string DPP_EXPORT ts_to_string(time_t ts); -} // namespace dpp +} diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index 1330b7e0b2..ceb9d92829 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -1271,5 +1271,5 @@ class DPP_EXPORT discord_voice_client : public websocket_client void process_mls_group_rosters(const std::map>& rmap); }; -} // namespace dpp +} diff --git a/include/dpp/dispatcher.h b/include/dpp/dispatcher.h index 749f3a0454..be08488b7b 100644 --- a/include/dpp/dispatcher.h +++ b/include/dpp/dispatcher.h @@ -2198,5 +2198,5 @@ struct DPP_EXPORT entitlement_delete_t : public event_dispatch_t { entitlement deleted = {}; }; -} // namespace dpp +} diff --git a/include/dpp/dtemplate.h b/include/dpp/dtemplate.h index 098824e458..b0a2dc494b 100644 --- a/include/dpp/dtemplate.h +++ b/include/dpp/dtemplate.h @@ -112,4 +112,4 @@ class DPP_EXPORT dtemplate : public json_interface { */ typedef std::unordered_map dtemplate_map; -} // namespace dpp +} diff --git a/include/dpp/emoji.h b/include/dpp/emoji.h index 6249b4c9eb..7546ead720 100644 --- a/include/dpp/emoji.h +++ b/include/dpp/emoji.h @@ -249,4 +249,4 @@ class DPP_EXPORT emoji : public managed, public json_interface { */ typedef std::unordered_map emoji_map; -} // namespace dpp +} diff --git a/include/dpp/entitlement.h b/include/dpp/entitlement.h index 857b2691dd..fd181d6c5c 100644 --- a/include/dpp/entitlement.h +++ b/include/dpp/entitlement.h @@ -243,4 +243,4 @@ class DPP_EXPORT entitlement : public managed, public json_interface entitlement_map; -} // namespace dpp +} diff --git a/include/dpp/etf.h b/include/dpp/etf.h index 8e17ca3a96..f4e9f1d29b 100644 --- a/include/dpp/etf.h +++ b/include/dpp/etf.h @@ -708,4 +708,4 @@ class DPP_EXPORT etf_parser { std::string build(const nlohmann::json& j); }; -} // namespace dpp +} diff --git a/include/dpp/event.h b/include/dpp/event.h index 6921586755..1e34e1b365 100644 --- a/include/dpp/event.h +++ b/include/dpp/event.h @@ -156,4 +156,4 @@ event_decl(entitlement_create, ENTITLEMENT_CREATE); event_decl(entitlement_update, ENTITLEMENT_UPDATE); event_decl(entitlement_delete, ENTITLEMENT_DELETE); -} // namespace dpp::events +} diff --git a/include/dpp/event_router.h b/include/dpp/event_router.h index 2babc42e29..be8fc14d22 100644 --- a/include/dpp/event_router.h +++ b/include/dpp/event_router.h @@ -742,4 +742,4 @@ const T &awaitable::await_resume() { } #endif -} // namespace dpp +} diff --git a/include/dpp/exception.h b/include/dpp/exception.h index 1c60084240..3d5f41ff08 100644 --- a/include/dpp/exception.h +++ b/include/dpp/exception.h @@ -602,5 +602,5 @@ class exception : public std::exception # endif /* DPP_CORO */ #endif -} // namespace dpp +} diff --git a/include/dpp/guild.h b/include/dpp/guild.h index 86c9393f0b..b031371e20 100644 --- a/include/dpp/guild.h +++ b/include/dpp/guild.h @@ -2048,4 +2048,4 @@ typedef std::unordered_map guild_member_map; */ guild_member DPP_EXPORT find_guild_member(const snowflake guild_id, const snowflake user_id); -} // namespace dpp +} diff --git a/include/dpp/httpsclient.h b/include/dpp/httpsclient.h index 0090c68af4..5a0ff481cf 100644 --- a/include/dpp/httpsclient.h +++ b/include/dpp/httpsclient.h @@ -356,4 +356,4 @@ class DPP_EXPORT https_client : public ssl_client { }; -} // namespace dpp +} diff --git a/include/dpp/integration.h b/include/dpp/integration.h index 1e48c7be65..1dc78747fc 100644 --- a/include/dpp/integration.h +++ b/include/dpp/integration.h @@ -335,5 +335,5 @@ typedef std::unordered_map integration_map; */ typedef std::unordered_map connection_map; -} // namespace dpp +} diff --git a/include/dpp/intents.h b/include/dpp/intents.h index d225a9d5e1..f2e82b0c74 100644 --- a/include/dpp/intents.h +++ b/include/dpp/intents.h @@ -152,4 +152,4 @@ enum intents { i_unverified_default_intents = dpp::i_default_intents | dpp::i_message_content }; -} // namespace dpp +} diff --git a/include/dpp/invite.h b/include/dpp/invite.h index c20708056a..d1d9a939b9 100644 --- a/include/dpp/invite.h +++ b/include/dpp/invite.h @@ -242,4 +242,4 @@ class DPP_EXPORT invite : public json_interface { */ typedef std::unordered_map invite_map; -} // namespace dpp +} diff --git a/include/dpp/isa/avx.h b/include/dpp/isa/avx.h index b84d90b56a..6cae986288 100644 --- a/include/dpp/isa/avx.h +++ b/include/dpp/isa/avx.h @@ -107,6 +107,6 @@ namespace dpp { } }; -} // namespace dpp +} #endif \ No newline at end of file diff --git a/include/dpp/isa/avx2.h b/include/dpp/isa/avx2.h index 009127932a..29ed493e43 100644 --- a/include/dpp/isa/avx2.h +++ b/include/dpp/isa/avx2.h @@ -110,6 +110,6 @@ namespace dpp { } }; -} // namespace dpp +} #endif \ No newline at end of file diff --git a/include/dpp/isa/avx512.h b/include/dpp/isa/avx512.h index e5535da742..333a1a64f7 100644 --- a/include/dpp/isa/avx512.h +++ b/include/dpp/isa/avx512.h @@ -113,6 +113,6 @@ namespace dpp { } }; -} // namespace dpp +} #endif \ No newline at end of file diff --git a/include/dpp/isa/fallback.h b/include/dpp/isa/fallback.h index a7154233b2..5d246d4d29 100644 --- a/include/dpp/isa/fallback.h +++ b/include/dpp/isa/fallback.h @@ -76,4 +76,4 @@ namespace dpp { } }; -} // namespace dpp +} diff --git a/include/dpp/json_interface.h b/include/dpp/json_interface.h index 0fd209ed00..720b7a2eba 100644 --- a/include/dpp/json_interface.h +++ b/include/dpp/json_interface.h @@ -70,4 +70,4 @@ struct json_interface { } }; -} // namespace dpp +} diff --git a/include/dpp/managed.h b/include/dpp/managed.h index 4ccd2e5318..66d6b210a1 100644 --- a/include/dpp/managed.h +++ b/include/dpp/managed.h @@ -113,4 +113,4 @@ class DPP_EXPORT managed { } }; -} // namespace dpp +} diff --git a/include/dpp/message.h b/include/dpp/message.h index 44640af8d8..200f3f7a07 100644 --- a/include/dpp/message.h +++ b/include/dpp/message.h @@ -2651,4 +2651,4 @@ typedef std::unordered_map sticker_map; */ typedef std::unordered_map sticker_pack_map; -} // namespace dpp +} diff --git a/include/dpp/misc-enum.h b/include/dpp/misc-enum.h index 19fd2fcd9a..d9ac781f08 100644 --- a/include/dpp/misc-enum.h +++ b/include/dpp/misc-enum.h @@ -86,4 +86,4 @@ enum loglevel { ll_critical }; -} // namespace dpp +} diff --git a/include/dpp/once.h b/include/dpp/once.h index f81a02cfdb..ef24f205bb 100644 --- a/include/dpp/once.h +++ b/include/dpp/once.h @@ -43,4 +43,4 @@ template auto run_once() { return !std::exchange(called, true); }; -} // namespace dpp +} diff --git a/include/dpp/permissions.h b/include/dpp/permissions.h index 22b1b555ba..4124e3cd80 100644 --- a/include/dpp/permissions.h +++ b/include/dpp/permissions.h @@ -456,4 +456,4 @@ class DPP_EXPORT permission { } }; -} // namespace dpp +} diff --git a/include/dpp/presence.h b/include/dpp/presence.h index 7515b14bac..3918bf2d60 100644 --- a/include/dpp/presence.h +++ b/include/dpp/presence.h @@ -595,4 +595,4 @@ class DPP_EXPORT presence : public json_interface { */ typedef std::unordered_map presence_map; -} // namespace dpp +} diff --git a/include/dpp/prune.h b/include/dpp/prune.h index 36e6275f6d..08b7592597 100644 --- a/include/dpp/prune.h +++ b/include/dpp/prune.h @@ -77,4 +77,4 @@ struct DPP_EXPORT prune : public json_interface { json to_json(bool with_id = false) const; // Intentional shadow of json_interface, mostly present for documentation }; -} // namespace dpp +} diff --git a/include/dpp/queues.h b/include/dpp/queues.h index 3597e78931..c502647936 100644 --- a/include/dpp/queues.h +++ b/include/dpp/queues.h @@ -671,4 +671,4 @@ class DPP_EXPORT request_queue { bool is_globally_ratelimited() const; }; -} // namespace dpp +} diff --git a/include/dpp/restrequest.h b/include/dpp/restrequest.h index 93fdd27071..2fcff85a77 100644 --- a/include/dpp/restrequest.h +++ b/include/dpp/restrequest.h @@ -294,4 +294,4 @@ template inline void rest_request_vector(dpp::cluster* c, const char* b } -} // namespace dpp +} diff --git a/include/dpp/restresults.h b/include/dpp/restresults.h index c496f13c79..a78b9e9dfe 100644 --- a/include/dpp/restresults.h +++ b/include/dpp/restresults.h @@ -335,4 +335,4 @@ typedef std::function command_completion_e * @brief Automatically JSON encoded HTTP result */ typedef std::function json_encode_t; -} // namespace dpp +} diff --git a/include/dpp/role.h b/include/dpp/role.h index a3da13f367..1a76862823 100644 --- a/include/dpp/role.h +++ b/include/dpp/role.h @@ -994,5 +994,5 @@ typedef std::unordered_map role_map; */ typedef std::vector application_role_connection_metadata_list; -} // namespace dpp +} diff --git a/include/dpp/sku.h b/include/dpp/sku.h index f9d7c03908..7515a06260 100644 --- a/include/dpp/sku.h +++ b/include/dpp/sku.h @@ -173,4 +173,4 @@ class DPP_EXPORT sku : public managed, public json_interface { */ typedef std::unordered_map sku_map; -} // namespace dpp +} diff --git a/include/dpp/snowflake.h b/include/dpp/snowflake.h index 109f16a53a..871dca729b 100644 --- a/include/dpp/snowflake.h +++ b/include/dpp/snowflake.h @@ -269,7 +269,7 @@ class DPP_EXPORT snowflake final { } }; -} // namespace dpp +} template<> struct std::hash diff --git a/include/dpp/sslclient.h b/include/dpp/sslclient.h index e8e17e2c82..00371ef287 100644 --- a/include/dpp/sslclient.h +++ b/include/dpp/sslclient.h @@ -257,4 +257,4 @@ class DPP_EXPORT ssl_client virtual void log(dpp::loglevel severity, const std::string &msg) const; }; -} // namespace dpp +} diff --git a/include/dpp/stage_instance.h b/include/dpp/stage_instance.h index 6b0d2719a0..2bd90884a8 100644 --- a/include/dpp/stage_instance.h +++ b/include/dpp/stage_instance.h @@ -109,4 +109,4 @@ struct DPP_EXPORT stage_instance : public managed, public json_interface stage_instance_map; -} // namespace dpp +} diff --git a/include/dpp/stringops.h b/include/dpp/stringops.h index 9383fa4d06..cd99d9cc4f 100644 --- a/include/dpp/stringops.h +++ b/include/dpp/stringops.h @@ -220,4 +220,4 @@ template std::string leading_zeroes(T i, size_t width) return stream.str(); } -} // namespace dpp +} diff --git a/include/dpp/sync.h b/include/dpp/sync.h index 3c69f43a05..fdce669b2d 100644 --- a/include/dpp/sync.h +++ b/include/dpp/sync.h @@ -78,4 +78,4 @@ template T sync(class cluster* c, F func, Ts&& return _f.get(); } -} // namespace dpp +} diff --git a/include/dpp/timed_listener.h b/include/dpp/timed_listener.h index c5d7d0229b..d4dca777fc 100644 --- a/include/dpp/timed_listener.h +++ b/include/dpp/timed_listener.h @@ -102,4 +102,4 @@ template class timed_listene } }; -} // namespace dpp +} diff --git a/include/dpp/timer.h b/include/dpp/timer.h index e3e10943d1..c3dfbfa97e 100644 --- a/include/dpp/timer.h +++ b/include/dpp/timer.h @@ -129,4 +129,4 @@ class DPP_EXPORT oneshot_timer ~oneshot_timer(); }; -} // namespace dpp +} diff --git a/include/dpp/user.h b/include/dpp/user.h index cc7acadadd..57a8d73444 100644 --- a/include/dpp/user.h +++ b/include/dpp/user.h @@ -581,4 +581,4 @@ void from_json(const nlohmann::json& j, user_identified& u); */ typedef std::unordered_map user_map; -} // namespace dpp +} diff --git a/include/dpp/utility.h b/include/dpp/utility.h index 6654606fc3..cf6c417104 100644 --- a/include/dpp/utility.h +++ b/include/dpp/utility.h @@ -1066,4 +1066,4 @@ struct alignas(T) dummy { }; } // namespace utility -} // namespace dpp +} diff --git a/include/dpp/voiceregion.h b/include/dpp/voiceregion.h index 15d9306294..f3fd56055c 100644 --- a/include/dpp/voiceregion.h +++ b/include/dpp/voiceregion.h @@ -123,4 +123,4 @@ class DPP_EXPORT voiceregion : public json_interface { */ typedef std::unordered_map voiceregion_map; -} // namespace dpp +} diff --git a/include/dpp/voicestate.h b/include/dpp/voicestate.h index b5f9b55bcf..dc29652524 100644 --- a/include/dpp/voicestate.h +++ b/include/dpp/voicestate.h @@ -176,4 +176,4 @@ class DPP_EXPORT voicestate : public json_interface { /** A container of voicestates */ typedef std::unordered_map voicestate_map; -} // namespace dpp +} diff --git a/include/dpp/webhook.h b/include/dpp/webhook.h index 304565c26b..bef620814b 100644 --- a/include/dpp/webhook.h +++ b/include/dpp/webhook.h @@ -196,4 +196,4 @@ class DPP_EXPORT webhook : public managed, public json_interface { */ typedef std::unordered_map webhook_map; -} // namespace dpp +} diff --git a/include/dpp/wsclient.h b/include/dpp/wsclient.h index ee476c14f9..fbbf72dee7 100644 --- a/include/dpp/wsclient.h +++ b/include/dpp/wsclient.h @@ -237,4 +237,4 @@ class DPP_EXPORT websocket_client : public ssl_client { void send_close_packet(); }; -} // namespace dpp +} diff --git a/src/dpp/application.cpp b/src/dpp/application.cpp index e1c79c4848..1d2878d96d 100644 --- a/src/dpp/application.cpp +++ b/src/dpp/application.cpp @@ -21,10 +21,7 @@ ************************************************************************************/ #include #include -#include -#include #include -#include namespace dpp { @@ -168,5 +165,4 @@ std::string application::get_icon_url(uint16_t size, const image_type format) co return ""; } -} // namespace dpp - +} diff --git a/src/dpp/auditlog.cpp b/src/dpp/auditlog.cpp index 9abc95f121..2dcf8fb99f 100644 --- a/src/dpp/auditlog.cpp +++ b/src/dpp/auditlog.cpp @@ -74,5 +74,5 @@ auditlog& auditlog::fill_from_json_impl(nlohmann::json* j) { return *this; } -} // namespace dpp +} diff --git a/src/dpp/automod.cpp b/src/dpp/automod.cpp index 219d347859..0492f49a97 100644 --- a/src/dpp/automod.cpp +++ b/src/dpp/automod.cpp @@ -186,5 +186,5 @@ json automod_rule::to_json_impl(bool with_id) const { return j; } -} // namespace dpp +} diff --git a/src/dpp/ban.cpp b/src/dpp/ban.cpp index aee056b68e..a697b35c70 100644 --- a/src/dpp/ban.cpp +++ b/src/dpp/ban.cpp @@ -40,5 +40,5 @@ ban& ban::fill_from_json_impl(nlohmann::json* j) { return *this; } -} // namespace dpp +} diff --git a/src/dpp/cache.cpp b/src/dpp/cache.cpp index 715b829dd8..256e4e16f0 100644 --- a/src/dpp/cache.cpp +++ b/src/dpp/cache.cpp @@ -21,10 +21,8 @@ ************************************************************************************/ #include #include -#include #include #include -#include namespace dpp { @@ -85,4 +83,4 @@ cache_helper(role, role_cache, find_role, get_role_cache, get_role_count); cache_helper(guild, guild_cache, find_guild, get_guild_cache, get_guild_count); cache_helper(emoji, emoji_cache, find_emoji, get_emoji_cache, get_emoji_count); -} // namespace dpp +} diff --git a/src/dpp/channel.cpp b/src/dpp/channel.cpp index 4903b60f81..a12be0f59d 100644 --- a/src/dpp/channel.cpp +++ b/src/dpp/channel.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -580,4 +579,4 @@ forum_layout_type channel::get_default_forum_layout() const { } -} // namespace dpp +} diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index 26e333d194..90d4cb12c0 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -21,17 +21,9 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include namespace dpp { diff --git a/src/dpp/cluster/appcommand.cpp b/src/dpp/cluster/appcommand.cpp index 80c3308447..ae131da0ab 100644 --- a/src/dpp/cluster/appcommand.cpp +++ b/src/dpp/cluster/appcommand.cpp @@ -191,4 +191,4 @@ void cluster::interaction_followup_get_original(const std::string &token, comman rest_request(this, API_PATH "/webhooks",std::to_string(me.id), utility::url_encode(token) + "/messages/@original", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/automod.cpp b/src/dpp/cluster/automod.cpp index f4584baab7..c0d2d534aa 100644 --- a/src/dpp/cluster/automod.cpp +++ b/src/dpp/cluster/automod.cpp @@ -43,4 +43,4 @@ void cluster::automod_rule_delete(snowflake guild_id, snowflake rule_id, command rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/auto-moderation/rules/" + std::to_string(rule_id), m_delete, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/channel.cpp b/src/dpp/cluster/channel.cpp index 4e0e41cc80..83e317f71c 100644 --- a/src/dpp/cluster/channel.cpp +++ b/src/dpp/cluster/channel.cpp @@ -101,4 +101,4 @@ void cluster::channel_set_voice_status(snowflake channel_id, const std::string& rest_request(this, API_PATH "/channels", std::to_string(channel_id), "voice-status", m_put, j.dump(-1, ' ', false, json::error_handler_t::replace), callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/confirmation.cpp b/src/dpp/cluster/confirmation.cpp index 07072ccaf2..6e48b138a2 100644 --- a/src/dpp/cluster/confirmation.cpp +++ b/src/dpp/cluster/confirmation.cpp @@ -161,4 +161,4 @@ error_info confirmation_callback_t::get_error() const { return {}; } -} // namespace dpp +} diff --git a/src/dpp/cluster/dm.cpp b/src/dpp/cluster/dm.cpp index cba8af9654..be895f7690 100644 --- a/src/dpp/cluster/dm.cpp +++ b/src/dpp/cluster/dm.cpp @@ -63,4 +63,4 @@ void cluster::gdm_remove(snowflake channel_id, snowflake user_id, command_comple rest_request(this, API_PATH "/channels", std::to_string(channel_id), "recipients/" + std::to_string(user_id), m_delete, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/emoji.cpp b/src/dpp/cluster/emoji.cpp index 626707d13c..9e2f2b8461 100644 --- a/src/dpp/cluster/emoji.cpp +++ b/src/dpp/cluster/emoji.cpp @@ -81,4 +81,4 @@ void cluster::application_emoji_delete(snowflake emoji_id, command_completion_ev rest_request(this, API_PATH "/applications", me.id.str(), "emojis/" + emoji_id.str(), m_delete, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/entitlement.cpp b/src/dpp/cluster/entitlement.cpp index d2b120772e..fa96e4c2b1 100644 --- a/src/dpp/cluster/entitlement.cpp +++ b/src/dpp/cluster/entitlement.cpp @@ -81,4 +81,4 @@ void cluster::entitlement_consume(const class snowflake entitlement_id, command_ rest_request(this, API_PATH "/applications", me.id.str(), "entitlements/" + entitlement_id.str() + "/consume", m_post, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/gateway.cpp b/src/dpp/cluster/gateway.cpp index 7da7a81dd4..85bcfd6ca1 100644 --- a/src/dpp/cluster/gateway.cpp +++ b/src/dpp/cluster/gateway.cpp @@ -26,4 +26,4 @@ void cluster::get_gateway_bot(command_completion_event_t callback) { rest_request(this, API_PATH "/gateway", "bot", "", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/guild.cpp b/src/dpp/cluster/guild.cpp index bf58372f69..75396c907b 100644 --- a/src/dpp/cluster/guild.cpp +++ b/src/dpp/cluster/guild.cpp @@ -169,4 +169,4 @@ void cluster::guild_edit_welcome_screen(snowflake guild_id, const struct welcome } -} // namespace dpp +} diff --git a/src/dpp/cluster/guild_member.cpp b/src/dpp/cluster/guild_member.cpp index 28e3b953b0..8ab690ea94 100644 --- a/src/dpp/cluster/guild_member.cpp +++ b/src/dpp/cluster/guild_member.cpp @@ -152,4 +152,4 @@ void cluster::guild_search_members(snowflake guild_id, const std::string& query, }); } -} // namespace dpp +} diff --git a/src/dpp/cluster/invite.cpp b/src/dpp/cluster/invite.cpp index 5d73f6aed7..1e03ed6555 100644 --- a/src/dpp/cluster/invite.cpp +++ b/src/dpp/cluster/invite.cpp @@ -35,4 +35,4 @@ void cluster::invite_get(const std::string &invite_code, command_completion_even rest_request(this, API_PATH "/invites", utility::url_encode(invite_code) + "?with_counts=true&with_expiration=true", "", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/json_interface.cpp b/src/dpp/cluster/json_interface.cpp index 76863321ce..3af8435841 100644 --- a/src/dpp/cluster/json_interface.cpp +++ b/src/dpp/cluster/json_interface.cpp @@ -25,4 +25,4 @@ namespace dpp { -} // namespace dpp +} diff --git a/src/dpp/cluster/message.cpp b/src/dpp/cluster/message.cpp index e1d4943b59..b1922902a1 100644 --- a/src/dpp/cluster/message.cpp +++ b/src/dpp/cluster/message.cpp @@ -208,4 +208,4 @@ void cluster::channel_pins_get(snowflake channel_id, command_completion_event_t rest_request_list(this, API_PATH "/channels", std::to_string(channel_id), "pins", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/role.cpp b/src/dpp/cluster/role.cpp index 2a2065a8f2..371c6256bb 100644 --- a/src/dpp/cluster/role.cpp +++ b/src/dpp/cluster/role.cpp @@ -70,4 +70,4 @@ void cluster::user_application_role_connection_update(snowflake application_id, rest_request(this, API_PATH "/users/@me/applications", std::to_string(application_id), "role-connection", m_put, connection.build_json(), callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/scheduled_event.cpp b/src/dpp/cluster/scheduled_event.cpp index ddc7ea16c6..fbf91ca18c 100644 --- a/src/dpp/cluster/scheduled_event.cpp +++ b/src/dpp/cluster/scheduled_event.cpp @@ -68,4 +68,4 @@ void cluster::guild_event_get(snowflake guild_id, snowflake event_id, command_co rest_request(this, API_PATH "/guilds", std::to_string(guild_id), "/scheduled-events/" + std::to_string(event_id) + "?with_user_count=true", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/sku.cpp b/src/dpp/cluster/sku.cpp index 20f23f3e77..2c44c30c01 100644 --- a/src/dpp/cluster/sku.cpp +++ b/src/dpp/cluster/sku.cpp @@ -27,4 +27,4 @@ void cluster::skus_get(command_completion_event_t callback) { rest_request_list(this, API_PATH "/applications", me.id.str(), "entitlements", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/stage_instance.cpp b/src/dpp/cluster/stage_instance.cpp index 9257f90a6d..ac9146d568 100644 --- a/src/dpp/cluster/stage_instance.cpp +++ b/src/dpp/cluster/stage_instance.cpp @@ -39,4 +39,4 @@ void cluster::stage_instance_delete(const snowflake channel_id, command_completi rest_request(this, API_PATH "/stage-instances", std::to_string(channel_id), "", m_delete, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/sticker.cpp b/src/dpp/cluster/sticker.cpp index 9f61521a44..bc5ba5a0b5 100644 --- a/src/dpp/cluster/sticker.cpp +++ b/src/dpp/cluster/sticker.cpp @@ -55,4 +55,4 @@ void cluster::sticker_packs_get(command_completion_event_t callback) { rest_request_list(this, API_PATH "/sticker-packs", "", "", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/template.cpp b/src/dpp/cluster/template.cpp index f0503ff83f..bf01b136a2 100644 --- a/src/dpp/cluster/template.cpp +++ b/src/dpp/cluster/template.cpp @@ -60,4 +60,4 @@ void cluster::template_get(const std::string &code, command_completion_event_t c rest_request(this, API_PATH "/guilds", "templates", code, m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/thread.cpp b/src/dpp/cluster/thread.cpp index b3c109406e..bf2205b51b 100644 --- a/src/dpp/cluster/thread.cpp +++ b/src/dpp/cluster/thread.cpp @@ -191,4 +191,4 @@ void cluster::thread_get(snowflake thread_id, command_completion_event_t callbac rest_request(this, API_PATH "/channels", std::to_string(thread_id), "", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/timer.cpp b/src/dpp/cluster/timer.cpp index e6d7df1814..a6520306f2 100644 --- a/src/dpp/cluster/timer.cpp +++ b/src/dpp/cluster/timer.cpp @@ -146,4 +146,4 @@ oneshot_timer::~oneshot_timer() { cancel(); } -} // namespace dpp +} diff --git a/src/dpp/cluster/user.cpp b/src/dpp/cluster/user.cpp index b3504ceae2..616c5c101f 100644 --- a/src/dpp/cluster/user.cpp +++ b/src/dpp/cluster/user.cpp @@ -129,4 +129,4 @@ void cluster::user_get_cached(snowflake user_id, command_completion_event_t call rest_request(this, API_PATH "/users", std::to_string(user_id), "", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/voice.cpp b/src/dpp/cluster/voice.cpp index ea78a487a4..c99bc45303 100644 --- a/src/dpp/cluster/voice.cpp +++ b/src/dpp/cluster/voice.cpp @@ -32,4 +32,4 @@ void cluster::guild_get_voice_regions(snowflake guild_id, command_completion_eve rest_request_list(this, API_PATH "/guilds", std::to_string(guild_id), "regions", m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/cluster/webhook.cpp b/src/dpp/cluster/webhook.cpp index 5231d19e40..8ebf9370e4 100644 --- a/src/dpp/cluster/webhook.cpp +++ b/src/dpp/cluster/webhook.cpp @@ -117,4 +117,4 @@ void cluster::get_webhook_with_token(snowflake webhook_id, const std::string &to rest_request(this, API_PATH "/webhooks", std::to_string(webhook_id), utility::url_encode(token), m_get, "", callback); } -} // namespace dpp +} diff --git a/src/dpp/commandhandler.cpp b/src/dpp/commandhandler.cpp index e337b0eee9..9101bbd477 100644 --- a/src/dpp/commandhandler.cpp +++ b/src/dpp/commandhandler.cpp @@ -20,7 +20,6 @@ ************************************************************************************/ #include #include -#include #include #include #include @@ -437,4 +436,4 @@ void commandhandler::thonk(command_source source, command_completion_event_t cal thinking(source, callback); } -} // namespace dpp +} diff --git a/src/dpp/discordclient.cpp b/src/dpp/discordclient.cpp index 09e5258ece..cf43b76fca 100644 --- a/src/dpp/discordclient.cpp +++ b/src/dpp/discordclient.cpp @@ -20,7 +20,6 @@ * ************************************************************************************/ #include -#include #include #include #include @@ -30,18 +29,6 @@ #include #include #include -#ifdef _WIN32 - #include - #include - #include -#else - #include - #include - #include - #include - #include - #include -#endif #define PATH_UNCOMPRESSED_JSON "/?v=" DISCORD_API_VERSION "&encoding=json" #define PATH_COMPRESSED_JSON "/?v=" DISCORD_API_VERSION "&encoding=json&compress=zlib-stream" @@ -732,4 +719,4 @@ voiceconn& voiceconn::connect(snowflake guild_id) { } -} // namespace dpp +} diff --git a/src/dpp/discordevents.cpp b/src/dpp/discordevents.cpp index f3e2aebb68..fb58faf610 100644 --- a/src/dpp/discordevents.cpp +++ b/src/dpp/discordevents.cpp @@ -22,7 +22,7 @@ /* OpenBSD errors when xopen_source is defined. * We want to make sure that OpenBSD does not define it. */ -#if !defined(__OpenBSD__) +#ifndef __OpenBSD__ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE #endif @@ -35,11 +35,7 @@ #include #include #include -#include -#include -#include #include -#include #include #include @@ -439,4 +435,4 @@ void discord_client::handle_event(const std::string &event, json &j, const std:: } } -} // namespace dpp +} diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 4a4f484968..5b241d1122 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -21,16 +21,6 @@ ************************************************************************************/ #include -#ifdef _WIN32 - #include - #include - #include -#else - #include - #include - #include -#endif -#include #include #include #include @@ -460,4 +450,4 @@ discord_voice_client& discord_voice_client::send_stop_frames(bool send_now) { return *this; } -} // namespace dpp +} diff --git a/src/dpp/dispatcher.cpp b/src/dpp/dispatcher.cpp index 6ac9775d40..db8ea2e888 100644 --- a/src/dpp/dispatcher.cpp +++ b/src/dpp/dispatcher.cpp @@ -286,4 +286,4 @@ void voice_receive_t::reassign(discord_voice_client* vc, snowflake _user_id, con audio_size = audio_data.size(); } -} // namespace dpp +} diff --git a/src/dpp/dns.cpp b/src/dpp/dns.cpp index 257b9b2315..42aed3ce8f 100644 --- a/src/dpp/dns.cpp +++ b/src/dpp/dns.cpp @@ -21,7 +21,6 @@ ************************************************************************************/ #include -#include #include #include #include diff --git a/src/dpp/dtemplate.cpp b/src/dpp/dtemplate.cpp index 8f67e0efd6..1ed6f53905 100644 --- a/src/dpp/dtemplate.cpp +++ b/src/dpp/dtemplate.cpp @@ -57,4 +57,4 @@ json dtemplate::to_json_impl(bool with_id) const { }; } -} // namespace dpp +} diff --git a/src/dpp/emoji.cpp b/src/dpp/emoji.cpp index b8d0350e20..4d90982e64 100644 --- a/src/dpp/emoji.cpp +++ b/src/dpp/emoji.cpp @@ -22,7 +22,6 @@ #include #include #include -#include namespace dpp { @@ -130,5 +129,5 @@ std::string emoji::get_url(uint16_t size, const dpp::image_type format, bool pre } -} // namespace dpp +} diff --git a/src/dpp/entitlement.cpp b/src/dpp/entitlement.cpp index f3ee034a04..b30871ce58 100644 --- a/src/dpp/entitlement.cpp +++ b/src/dpp/entitlement.cpp @@ -83,4 +83,4 @@ bool entitlement::is_consumed() const { return flags & entitlement_flags::ent_consumed; } -} // namespace dpp +} diff --git a/src/dpp/etf.cpp b/src/dpp/etf.cpp index a76f5d9c41..2b4c25f657 100644 --- a/src/dpp/etf.cpp +++ b/src/dpp/etf.cpp @@ -33,8 +33,6 @@ ************************************************************************************/ #include #include -#include -#include #include #include #include @@ -729,5 +727,5 @@ etf_buffer::etf_buffer(size_t initial) { etf_buffer::~etf_buffer() = default; -} // namespace dpp +} diff --git a/src/dpp/guild.cpp b/src/dpp/guild.cpp index 7751d6abea..0cecaaea4c 100644 --- a/src/dpp/guild.cpp +++ b/src/dpp/guild.cpp @@ -20,9 +20,6 @@ ************************************************************************************/ #include #include -#include -#include -#include #include #include #include @@ -1196,4 +1193,4 @@ onboarding &onboarding::set_enabled(const bool is_enabled) { } -} // namespace dpp +} diff --git a/src/dpp/httpsclient.cpp b/src/dpp/httpsclient.cpp index 9ac8faa021..8c7cff3258 100644 --- a/src/dpp/httpsclient.cpp +++ b/src/dpp/httpsclient.cpp @@ -27,8 +27,6 @@ #include #include #include -#include -#include namespace dpp { @@ -358,4 +356,4 @@ http_connect_info https_client::get_host_info(std::string url) { return hci; } -} // namespace dpp +} diff --git a/src/dpp/integration.cpp b/src/dpp/integration.cpp index c8e870fde1..e2cd59b51f 100644 --- a/src/dpp/integration.cpp +++ b/src/dpp/integration.cpp @@ -25,8 +25,6 @@ #include #include - - namespace dpp { using json = nlohmann::json; @@ -150,4 +148,4 @@ connection& connection::fill_from_json_impl(nlohmann::json* j) { return *this; } -} // namespace dpp +} diff --git a/src/dpp/invite.cpp b/src/dpp/invite.cpp index c063ac4aed..b33435f6e9 100644 --- a/src/dpp/invite.cpp +++ b/src/dpp/invite.cpp @@ -23,8 +23,6 @@ #include #include - - namespace dpp { using json = nlohmann::json; @@ -117,4 +115,4 @@ invite &invite::set_unique(const bool is_unique) { return *this; } -} // namespace dpp +} diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index 8c7efa1fe4..cb96f4edaa 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -1548,4 +1548,4 @@ sticker& sticker::set_file_content(std::string_view fc) { } -} // namespace dpp +} diff --git a/src/dpp/permissions.cpp b/src/dpp/permissions.cpp index 02dd8325d7..58eefaa3ce 100644 --- a/src/dpp/permissions.cpp +++ b/src/dpp/permissions.cpp @@ -27,4 +27,4 @@ permission::operator nlohmann::json() const { return std::to_string(value); } -} // namespace dpp +} diff --git a/src/dpp/presence.cpp b/src/dpp/presence.cpp index 34809b1c4c..7b40dc9a0d 100644 --- a/src/dpp/presence.cpp +++ b/src/dpp/presence.cpp @@ -21,12 +21,8 @@ ************************************************************************************/ #include #include -#include -#include #include - - namespace dpp { using json = nlohmann::json; @@ -35,8 +31,8 @@ std::string activity::get_large_asset_url(uint16_t size, const image_type format if (!this->assets.large_image.empty() && this->application_id && this->assets.large_image.find(':') == std::string::npos) { // make sure it's not a prefixed proxy image return utility::cdn_endpoint_url({ i_jpg, i_png, i_webp }, - "app-assets/" + std::to_string(this->application_id) + "/" + this->assets.large_image, - format, size); + "app-assets/" + std::to_string(this->application_id) + "/" + this->assets.large_image, + format, size); } else { return std::string(); } @@ -46,8 +42,8 @@ std::string activity::get_small_asset_url(uint16_t size, const image_type format if (!this->assets.small_image.empty() && this->application_id && this->assets.small_image.find(':') == std::string::npos) { // make sure it's not a prefixed proxy image return utility::cdn_endpoint_url({ i_jpg, i_png, i_webp }, - "app-assets/" + std::to_string(this->application_id) + "/" + this->assets.small_image, - format, size); + "app-assets/" + std::to_string(this->application_id) + "/" + this->assets.small_image, + format, size); } else { return std::string(); } @@ -308,4 +304,4 @@ presence_status presence::status() const { return (presence_status)((flags >> PF_SHIFT_MAIN) & PF_STATUS_MASK); } -} // namespace dpp +} diff --git a/src/dpp/prune.cpp b/src/dpp/prune.cpp index afd7f9ae52..befea860f0 100644 --- a/src/dpp/prune.cpp +++ b/src/dpp/prune.cpp @@ -51,4 +51,4 @@ json prune::to_json(bool with_id) const { return to_json_impl(with_id); } -} // namespace dpp +} diff --git a/src/dpp/queues.cpp b/src/dpp/queues.cpp index 8505606556..96aa1d5288 100644 --- a/src/dpp/queues.cpp +++ b/src/dpp/queues.cpp @@ -28,7 +28,6 @@ #include #include #include -#include namespace dpp { @@ -480,4 +479,4 @@ bool request_queue::is_globally_ratelimited() const return this->globally_ratelimited; } -} // namespace dpp +} diff --git a/src/dpp/role.cpp b/src/dpp/role.cpp index 89643f210f..877cf6d0a4 100644 --- a/src/dpp/role.cpp +++ b/src/dpp/role.cpp @@ -23,12 +23,8 @@ #include #include #include -#include -#include #include - - namespace dpp { using json = nlohmann::json; @@ -485,4 +481,4 @@ json application_role_connection::to_json_impl(bool with_id) const { } -} // namespace dpp +} diff --git a/src/dpp/scheduled_event.cpp b/src/dpp/scheduled_event.cpp index fe7e2c7a4c..2af52a4e5f 100644 --- a/src/dpp/scheduled_event.cpp +++ b/src/dpp/scheduled_event.cpp @@ -19,7 +19,6 @@ * ************************************************************************************/ #include -#include #include #include #include @@ -193,4 +192,4 @@ json scheduled_event::to_json_impl(bool with_id) const { return j; } -} // namespace dpp +} diff --git a/src/dpp/sku.cpp b/src/dpp/sku.cpp index 170a158159..52b0b62161 100644 --- a/src/dpp/sku.cpp +++ b/src/dpp/sku.cpp @@ -86,4 +86,4 @@ bool sku::is_user_subscription() const { return flags & sku_flags::sku_user_subscription; } -} // namespace dpp +} diff --git a/src/dpp/slashcommand.cpp b/src/dpp/slashcommand.cpp index 77dd4bfebe..782393ccde 100644 --- a/src/dpp/slashcommand.cpp +++ b/src/dpp/slashcommand.cpp @@ -20,7 +20,6 @@ ************************************************************************************/ #include #include -#include #include #include #include @@ -941,4 +940,4 @@ std::string command_interaction::get_mention() const { std::string slashcommand::get_mention() const { return dpp::utility::slashcommand_mention(id, name); } -} // namespace dpp +} diff --git a/src/dpp/snowflake.cpp b/src/dpp/snowflake.cpp index 72d566756c..2257b3158c 100644 --- a/src/dpp/snowflake.cpp +++ b/src/dpp/snowflake.cpp @@ -44,4 +44,4 @@ snowflake::operator json() const { return std::to_string(value); } -} // namespace dpp +} diff --git a/src/dpp/sslclient.cpp b/src/dpp/sslclient.cpp index 54698eb0e4..7cdf92150e 100644 --- a/src/dpp/sslclient.cpp +++ b/src/dpp/sslclient.cpp @@ -37,20 +37,13 @@ #else /* Anyting other than Windows (e.g. sane OSes) */ #include - #include - #include - #include #include - #include #include #endif -#include -#include -#include +#include #include #include -#include -#include +#include #include #include /* Windows specific OpenSSL symbol weirdness */ @@ -676,4 +669,4 @@ ssl_client::~ssl_client() cleanup(); } -} // namespace dpp +} diff --git a/src/dpp/stage_instance.cpp b/src/dpp/stage_instance.cpp index 4fde6c9dd3..dc11433e97 100644 --- a/src/dpp/stage_instance.cpp +++ b/src/dpp/stage_instance.cpp @@ -55,4 +55,4 @@ json stage_instance::to_json_impl(bool with_id) const { return j; } -} // namespace dpp +} diff --git a/src/dpp/thread.cpp b/src/dpp/thread.cpp index af661fe663..5ffc1f44f7 100644 --- a/src/dpp/thread.cpp +++ b/src/dpp/thread.cpp @@ -22,7 +22,6 @@ #include #include - namespace dpp { thread_member& thread_member::fill_from_json_impl(nlohmann::json* j) { diff --git a/src/dpp/user.cpp b/src/dpp/user.cpp index 64f21ae898..7f2d08cf4d 100644 --- a/src/dpp/user.cpp +++ b/src/dpp/user.cpp @@ -24,8 +24,8 @@ #include namespace dpp { -using json = nlohmann:: -json; + +using json = nlohmann::json; /* A mapping of discord's flag values to our bitmap (they're different bit positions to fit other stuff in) */ std::map usermap = { @@ -46,12 +46,7 @@ std::map usermap = { { 1 << 22, dpp::u_active_developer}, }; -user::user() : - managed(), - flags(0), - discriminator(0), - refcount(1) -{ +user::user() : managed(), flags(0), discriminator(0), refcount(1) { } std::string user::get_mention(const snowflake& id) { @@ -98,8 +93,8 @@ std::string user::get_avatar_url(uint16_t size, const image_type format, bool pr return get_default_avatar_url(); } else if (this->id) { return utility::cdn_endpoint_url_hash({ i_jpg, i_png, i_webp, i_gif }, - "avatars/" + std::to_string(this->id), this->avatar.to_string(), - format, size, prefer_animated, has_animated_icon()); + "avatars/" + std::to_string(this->id), this->avatar.to_string(), + format, size, prefer_animated, has_animated_icon()); } else { return std::string(); } @@ -108,12 +103,12 @@ std::string user::get_avatar_url(uint16_t size, const image_type format, bool pr std::string user::get_default_avatar_url() const { if (this->discriminator) { return utility::cdn_endpoint_url({ i_png }, - "embed/avatars/" + std::to_string(this->discriminator % 5), - i_png, 0); + "embed/avatars/" + std::to_string(this->discriminator % 5), + i_png, 0); } else if (this->id){ return utility::cdn_endpoint_url({ i_png }, - "embed/avatars/" + std::to_string((this->id >> 22) % 6), - i_png, 0); + "embed/avatars/" + std::to_string((this->id >> 22) % 6), + i_png, 0); } else { return std::string(); } @@ -122,8 +117,8 @@ std::string user::get_default_avatar_url() const { std::string user::get_avatar_decoration_url(uint16_t size) const { if (this->id) { return utility::cdn_endpoint_url_hash({ i_png }, - "avatar-decorations/" + std::to_string(this->id), this->avatar_decoration.to_string(), - i_png, size); + "avatar-decorations/" + std::to_string(this->id), this->avatar_decoration.to_string(), + i_png, size); } else { return std::string(); } @@ -253,8 +248,8 @@ bool user_identified::has_animated_banner() const { std::string user_identified::get_banner_url(uint16_t size, const image_type format, bool prefer_animated) const { if (!this->banner.to_string().empty() && this->id) { return utility::cdn_endpoint_url_hash({ i_jpg, i_png, i_webp, i_gif }, - "banners/" + std::to_string(this->id), this->banner.to_string(), - format, size, prefer_animated, has_animated_banner()); + "banners/" + std::to_string(this->id), this->banner.to_string(), + format, size, prefer_animated, has_animated_banner()); } else { return std::string(); } @@ -309,4 +304,4 @@ void from_json(const nlohmann::json& j, user& u) { } } -} // namespace dpp +} diff --git a/src/dpp/utility.cpp b/src/dpp/utility.cpp index b41be262fa..922fc4195e 100644 --- a/src/dpp/utility.cpp +++ b/src/dpp/utility.cpp @@ -21,7 +21,6 @@ ************************************************************************************/ #include #include -#include #include #include #include @@ -34,9 +33,6 @@ #include #include #include -#include -#include -#include #ifdef _WIN32 #include @@ -936,4 +932,4 @@ void set_thread_name(const std::string& name) { #endif } -} // namespace dpp::utility +} diff --git a/src/dpp/voice/enabled/audio_mix.cpp b/src/dpp/voice/enabled/audio_mix.cpp index 6d0f128e8c..c43d712313 100644 --- a/src/dpp/voice/enabled/audio_mix.cpp +++ b/src/dpp/voice/enabled/audio_mix.cpp @@ -21,14 +21,12 @@ ************************************************************************************/ #include -#include #include #include #include #include #include #include -#include #include namespace dpp { diff --git a/src/dpp/voice/enabled/cleanup.cpp b/src/dpp/voice/enabled/cleanup.cpp index 838000e884..5ae1d9c7e2 100644 --- a/src/dpp/voice/enabled/cleanup.cpp +++ b/src/dpp/voice/enabled/cleanup.cpp @@ -25,10 +25,8 @@ #include #include #include - #include #include "../../dave/encryptor.h" - #include "enabled.h" namespace dpp { diff --git a/src/dpp/voiceregion.cpp b/src/dpp/voiceregion.cpp index e3c9fc6349..22410228d7 100644 --- a/src/dpp/voiceregion.cpp +++ b/src/dpp/voiceregion.cpp @@ -72,5 +72,4 @@ bool voiceregion::is_custom() const { return flags & v_custom; } -} // namespace dpp - +} diff --git a/src/dpp/voicestate.cpp b/src/dpp/voicestate.cpp index f0bcbd6e9f..9968890200 100644 --- a/src/dpp/voicestate.cpp +++ b/src/dpp/voicestate.cpp @@ -90,5 +90,4 @@ bool voicestate::is_suppressed() const { return flags & vs_suppress; } -} // namespace dpp - +} diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 4c43c4df2c..cc5622fe06 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -22,7 +22,6 @@ #include #include #include -#include namespace dpp { @@ -101,5 +100,4 @@ webhook& webhook::load_image(const std::string &image_blob, const image_type typ return *this; } -} // namespace dpp - +} diff --git a/src/dpp/wsclient.cpp b/src/dpp/wsclient.cpp index 424c34d2b1..618c7e7282 100644 --- a/src/dpp/wsclient.cpp +++ b/src/dpp/wsclient.cpp @@ -331,4 +331,4 @@ void websocket_client::close() ssl_client::close(); } -} // namespace dpp +} From f356ea6aa0246035c11e6a89fd1001a40fd4b382 Mon Sep 17 00:00:00 2001 From: DPP VCPKG Bot Date: Sun, 20 Oct 2024 21:41:36 +0000 Subject: [PATCH 90/99] [bot] VCPKG info update [skip ci] --- vcpkg/ports/dpp/portfile.cmake | 2 +- vcpkg/ports/dpp/vcpkg.json | 2 +- vcpkg/versions/baseline.json | 932 ++++++++++++++++----------------- vcpkg/versions/d-/dpp.json | 4 +- 4 files changed, 470 insertions(+), 470 deletions(-) diff --git a/vcpkg/ports/dpp/portfile.cmake b/vcpkg/ports/dpp/portfile.cmake index 0af92ac4df..bc77cbaef3 100644 --- a/vcpkg/ports/dpp/portfile.cmake +++ b/vcpkg/ports/dpp/portfile.cmake @@ -2,7 +2,7 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO brainboxdotcc/DPP REF "v${VERSION}" - SHA512 664f669ecb2d8cafdfa6dd776fb429cde7d5692157d34f300ffe42cb7711dec69ce194ece5d372c8b070f979e2a341ecb7c018f8825a8acc148d17b3d4043c9b + SHA512 69fe3323aceb4ad52ec1fcfb38a8770e88c03ae0b6cb49768441b603e13659625720d984b992311fcca8ef863d40b8b7fb082996fae2d396e785b637b673a328 ) vcpkg_cmake_configure( diff --git a/vcpkg/ports/dpp/vcpkg.json b/vcpkg/ports/dpp/vcpkg.json index 05c1946a7b..eb86f373fe 100644 --- a/vcpkg/ports/dpp/vcpkg.json +++ b/vcpkg/ports/dpp/vcpkg.json @@ -1,6 +1,6 @@ { "name": "dpp", - "version": "10.0.32", + "version": "10.0.33", "description": "D++ Extremely Lightweight C++ Discord Library.", "homepage": "https://dpp.dev/", "license": "Apache-2.0", diff --git a/vcpkg/versions/baseline.json b/vcpkg/versions/baseline.json index bd267a5c4d..2f5f361937 100644 --- a/vcpkg/versions/baseline.json +++ b/vcpkg/versions/baseline.json @@ -34,7 +34,7 @@ }, "activemq-cpp": { "baseline": "3.9.5", - "port-version": 16 + "port-version": 17 }, "ada-url": { "baseline": "2.9.2", @@ -170,7 +170,7 @@ }, "apr": { "baseline": "1.7.5", - "port-version": 1 + "port-version": 2 }, "apr-util": { "baseline": "1.6.3", @@ -289,7 +289,7 @@ "port-version": 0 }, "async-mqtt": { - "baseline": "9.0.1", + "baseline": "9.0.2", "port-version": 0 }, "async-simple": { @@ -356,6 +356,10 @@ "baseline": "2017-06-21-c75699d2a8caa726260c29b6d7a0fd35f8f28933", "port-version": 2 }, + "aurora-au": { + "baseline": "0.3.5", + "port-version": 0 + }, "autobahn": { "baseline": "20.8.1", "port-version": 2 @@ -393,7 +397,7 @@ "port-version": 0 }, "aws-c-common": { - "baseline": "0.9.28", + "baseline": "0.9.30", "port-version": 0 }, "aws-c-compression": { @@ -437,7 +441,7 @@ "port-version": 0 }, "aws-sdk-cpp": { - "baseline": "1.11.420", + "baseline": "1.11.428", "port-version": 0 }, "azmq": { @@ -450,23 +454,23 @@ }, "azure-core-amqp-cpp": { "baseline": "1.0.0-beta.11", - "port-version": 0 + "port-version": 1 }, "azure-core-cpp": { "baseline": "1.14.0", - "port-version": 0 + "port-version": 1 }, "azure-core-tracing-opentelemetry-cpp": { "baseline": "1.0.0-beta.4", - "port-version": 4 + "port-version": 5 }, "azure-data-tables-cpp": { "baseline": "1.0.0-beta.4", - "port-version": 0 + "port-version": 1 }, "azure-identity-cpp": { "baseline": "1.10.0", - "port-version": 1 + "port-version": 2 }, "azure-iot-sdk-c": { "baseline": "2024-08-12", @@ -482,39 +486,39 @@ }, "azure-messaging-eventhubs-checkpointstore-blob-cpp": { "baseline": "1.0.0-beta.1", - "port-version": 3 + "port-version": 4 }, "azure-messaging-eventhubs-cpp": { "baseline": "1.0.0-beta.9", - "port-version": 1 + "port-version": 2 }, "azure-security-attestation-cpp": { "baseline": "1.1.0", - "port-version": 5 + "port-version": 6 }, "azure-security-keyvault-administration-cpp": { "baseline": "4.0.0-beta.5", - "port-version": 0 + "port-version": 1 }, "azure-security-keyvault-certificates-cpp": { "baseline": "4.2.1", - "port-version": 2 + "port-version": 3 }, "azure-security-keyvault-keys-cpp": { "baseline": "4.4.1", - "port-version": 2 + "port-version": 3 }, "azure-security-keyvault-secrets-cpp": { "baseline": "4.2.1", - "port-version": 2 + "port-version": 3 }, "azure-storage-blobs-cpp": { "baseline": "12.13.0", - "port-version": 0 + "port-version": 1 }, "azure-storage-common-cpp": { "baseline": "12.8.0", - "port-version": 0 + "port-version": 1 }, "azure-storage-cpp": { "baseline": "7.5.0", @@ -522,15 +526,15 @@ }, "azure-storage-files-datalake-cpp": { "baseline": "12.12.0", - "port-version": 0 + "port-version": 1 }, "azure-storage-files-shares-cpp": { "baseline": "12.11.0", - "port-version": 0 + "port-version": 1 }, "azure-storage-queues-cpp": { "baseline": "12.4.0", - "port-version": 0 + "port-version": 1 }, "azure-uamqp-c": { "baseline": "2024-08-12", @@ -733,636 +737,636 @@ "port-version": 0 }, "boost": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-accumulators": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-algorithm": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-align": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-any": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-array": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-asio": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-assert": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-assign": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-atomic": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-beast": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-bimap": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-bind": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-build": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-callable-traits": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-charconv": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-chrono": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-circular-buffer": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-cmake": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-cobalt": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-compat": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-compatibility": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-compute": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-concept-check": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-config": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-container": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-container-hash": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-context": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-contract": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-conversion": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-convert": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-core": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-coroutine": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-coroutine2": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-crc": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-date-time": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-describe": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-detail": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-dll": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-dynamic-bitset": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-endian": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-exception": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-fiber": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-filesystem": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-flyweight": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-foreach": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-format": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-function": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-function-types": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-functional": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-fusion": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-geometry": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-gil": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-graph": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-graph-parallel": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-hana": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-headers": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-heap": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-histogram": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-hof": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-icl": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-integer": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-interprocess": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-interval": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-intrusive": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-io": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-iostreams": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-iterator": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-json": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-lambda": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-lambda2": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-leaf": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-lexical-cast": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-local-function": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-locale": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-lockfree": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-log": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-logic": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-math": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-metaparse": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-move": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-mp11": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-mpi": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-mpl": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-msm": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-multi-array": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-multi-index": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-multiprecision": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-mysql": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-nowide": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-numeric-conversion": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-odeint": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-optional": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-outcome": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-parameter": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-parameter-python": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-pfr": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-phoenix": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-poly-collection": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-polygon": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-pool": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-predef": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-preprocessor": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-process": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-program-options": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-property-map": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-property-map-parallel": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-property-tree": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-proto": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-ptr-container": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-python": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-qvm": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-random": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-range": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-ratio": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-rational": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-redis": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-regex": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-safe-numerics": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-scope": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-scope-exit": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-serialization": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-signals2": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-smart-ptr": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-sort": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-spirit": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-stacktrace": { - "baseline": "1.85.0", - "port-version": 4 + "baseline": "1.86.0", + "port-version": 0 }, "boost-statechart": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-static-assert": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-static-string": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-stl-interfaces": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-system": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-test": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-thread": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-throw-exception": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-timer": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-tokenizer": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-tti": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-tuple": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-type-erasure": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-type-index": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-type-traits": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-typeof": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-ublas": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-uninstall": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-units": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-unordered": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-url": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-utility": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-uuid": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-variant": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-variant2": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-vcpkg-helpers": { "baseline": "1.84.0", "port-version": 0 }, "boost-vmd": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-wave": { - "baseline": "1.85.0", - "port-version": 2 + "baseline": "1.86.0", + "port-version": 0 }, "boost-winapi": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-xpressive": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boost-yap": { - "baseline": "1.85.0", - "port-version": 1 + "baseline": "1.86.0", + "port-version": 0 }, "boringssl": { "baseline": "2024-09-13", @@ -2070,7 +2074,7 @@ }, "ctbench": { "baseline": "1.3.4", - "port-version": 0 + "port-version": 1 }, "ctbignum": { "baseline": "2019-08-02", @@ -2289,8 +2293,8 @@ "port-version": 0 }, "directxmath": { - "baseline": "2024-02-14", - "port-version": 1 + "baseline": "2024-10-15", + "port-version": 0 }, "directxmesh": { "baseline": "2024-09-04", @@ -2325,7 +2329,7 @@ "port-version": 4 }, "discordcoreapi": { - "baseline": "2.0.6", + "baseline": "2.0.7", "port-version": 0 }, "discount": { @@ -2345,8 +2349,8 @@ "port-version": 0 }, "dlib": { - "baseline": "19.24", - "port-version": 4 + "baseline": "19.24.6", + "port-version": 0 }, "dlpack": { "baseline": "0.8", @@ -2377,7 +2381,7 @@ "port-version": 0 }, "dpp": { - "baseline": "10.0.32", + "baseline": "10.0.33", "port-version": 0 }, "draco": { @@ -2637,8 +2641,8 @@ "port-version": 1 }, "fakeit": { - "baseline": "2.4.0", - "port-version": 3 + "baseline": "2.4.1", + "port-version": 0 }, "fameta-counter": { "baseline": "2021-02-13", @@ -2673,7 +2677,7 @@ "port-version": 5 }, "fastdds": { - "baseline": "3.0.1", + "baseline": "3.1.0", "port-version": 0 }, "fastfeat": { @@ -2709,7 +2713,7 @@ "port-version": 1 }, "fbthrift": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "fcl": { @@ -2730,10 +2734,10 @@ }, "ffmpeg": { "baseline": "7.0.2", - "port-version": 4 + "port-version": 5 }, "ffnvcodec": { - "baseline": "12.1.14.0", + "baseline": "12.2.72.0", "port-version": 0 }, "fftw3": { @@ -2757,7 +2761,7 @@ "port-version": 0 }, "fizz": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "flagpp": { @@ -2841,7 +2845,7 @@ "port-version": 1 }, "folly": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "font-chef": { @@ -3005,17 +3009,13 @@ "port-version": 0 }, "gdal": { - "baseline": "3.9.2", + "baseline": "3.9.3", "port-version": 0 }, "gdcm": { - "baseline": "3.0.23", + "baseline": "3.0.24", "port-version": 0 }, - "gdcm2": { - "baseline": "deprecated", - "port-version": 1 - }, "gdk-pixbuf": { "baseline": "2.42.12", "port-version": 1 @@ -3126,7 +3126,7 @@ }, "glib": { "baseline": "2.80.0", - "port-version": 0 + "port-version": 1 }, "glib-networking": { "baseline": "2.78.0", @@ -3157,7 +3157,7 @@ "port-version": 3 }, "glslang": { - "baseline": "14.3.0", + "baseline": "15.0.0", "port-version": 0 }, "glui": { @@ -3426,7 +3426,7 @@ }, "hazelcast-cpp-client": { "baseline": "5.3.0", - "port-version": 0 + "port-version": 1 }, "hdf5": { "baseline": "1.14.4.3", @@ -3505,11 +3505,11 @@ "port-version": 1 }, "htscodecs": { - "baseline": "1.6.0", + "baseline": "1.6.1", "port-version": 0 }, "htslib": { - "baseline": "1.20", + "baseline": "1.21", "port-version": 0 }, "http-parser": { @@ -3845,7 +3845,7 @@ "port-version": 0 }, "json-rpc-cxx": { - "baseline": "0.3.1", + "baseline": "0.3.2", "port-version": 0 }, "json-schema-validator": { @@ -3873,7 +3873,7 @@ "port-version": 0 }, "jsonifier": { - "baseline": "0.9.96", + "baseline": "0.9.97", "port-version": 0 }, "jsonnet": { @@ -4273,7 +4273,7 @@ "port-version": 5 }, "libarchive": { - "baseline": "3.7.6", + "baseline": "3.7.7", "port-version": 0 }, "libass": { @@ -4293,8 +4293,8 @@ "port-version": 0 }, "libavif": { - "baseline": "1.0.4", - "port-version": 2 + "baseline": "1.1.1", + "port-version": 0 }, "libb2": { "baseline": "0.98.1", @@ -4448,6 +4448,10 @@ "baseline": "1.2.6", "port-version": 2 }, + "libedit": { + "baseline": "2024-08-08", + "port-version": 0 + }, "libenvpp": { "baseline": "1.4.1", "port-version": 0 @@ -4801,7 +4805,7 @@ "port-version": 0 }, "libmupdf": { - "baseline": "1.23.11", + "baseline": "1.24.10", "port-version": 0 }, "libmysofa": { @@ -4821,7 +4825,7 @@ "port-version": 0 }, "libnick": { - "baseline": "2024.9.2", + "baseline": "2024.10.0", "port-version": 0 }, "libnoise": { @@ -5012,6 +5016,10 @@ "baseline": "2019-11-11", "port-version": 4 }, + "librtpi": { + "baseline": "1.0.0", + "port-version": 1 + }, "librttopo": { "baseline": "1.1.0", "port-version": 8 @@ -5178,7 +5186,7 @@ }, "libtorch": { "baseline": "2.1.2", - "port-version": 6 + "port-version": 7 }, "libtorrent": { "baseline": "2.0.10", @@ -5253,7 +5261,7 @@ "port-version": 14 }, "libuv": { - "baseline": "1.49.0", + "baseline": "1.49.1", "port-version": 0 }, "libuvc": { @@ -5625,7 +5633,7 @@ "port-version": 1 }, "lunarg-vulkantools": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "lunasvg": { @@ -5717,7 +5725,7 @@ "port-version": 0 }, "mapbox-polylabel": { - "baseline": "1.1.0", + "baseline": "2.0.1", "port-version": 0 }, "mapbox-variant": { @@ -5941,7 +5949,7 @@ "port-version": 0 }, "mlpack": { - "baseline": "4.4.0", + "baseline": "4.5.0", "port-version": 0 }, "mman": { @@ -6081,7 +6089,7 @@ "port-version": 0 }, "msgpack-c": { - "baseline": "6.0.0", + "baseline": "6.1.0", "port-version": 0 }, "msgpack11": { @@ -6121,7 +6129,7 @@ "port-version": 1 }, "mujs": { - "baseline": "1.3.4", + "baseline": "1.3.5", "port-version": 0 }, "munit": { @@ -6141,7 +6149,7 @@ "port-version": 7 }, "mvfst": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "mygui": { @@ -6281,7 +6289,7 @@ "port-version": 4 }, "nghttp2": { - "baseline": "1.62.1", + "baseline": "1.63.0", "port-version": 0 }, "nghttp2-asio": { @@ -6317,19 +6325,15 @@ "port-version": 1 }, "nlopt": { - "baseline": "2.7.1", - "port-version": 1 - }, - "nmap": { - "baseline": "7.70", - "port-version": 12 + "baseline": "2.8.0", + "port-version": 0 }, "nmslib": { "baseline": "2.1.1", "port-version": 1 }, "nng": { - "baseline": "1.8.0", + "baseline": "1.9.0", "port-version": 0 }, "nngpp": { @@ -6533,11 +6537,11 @@ "port-version": 1 }, "onnx": { - "baseline": "1.15.0", - "port-version": 1 + "baseline": "1.16.2", + "port-version": 0 }, "onnx-optimizer": { - "baseline": "0.3.18", + "baseline": "0.3.19", "port-version": 0 }, "onnxruntime-gpu": { @@ -6565,16 +6569,16 @@ "port-version": 2 }, "openblas": { - "baseline": "0.3.27", - "port-version": 1 + "baseline": "0.3.28", + "port-version": 0 }, "opencascade": { "baseline": "7.8.1", "port-version": 1 }, "opencc": { - "baseline": "1.1.6", - "port-version": 1 + "baseline": "1.1.9", + "port-version": 0 }, "opencensus-cpp": { "baseline": "2021-08-26", @@ -6617,7 +6621,7 @@ "port-version": 1 }, "openexr": { - "baseline": "3.2.4", + "baseline": "3.3.1", "port-version": 0 }, "openfbx": { @@ -6645,8 +6649,8 @@ "port-version": 4 }, "openimageio": { - "baseline": "2.5.14.0", - "port-version": 1 + "baseline": "2.5.16.0", + "port-version": 0 }, "openjpeg": { "baseline": "2.5.2", @@ -6692,24 +6696,12 @@ "baseline": "3.3.2", "port-version": 1 }, - "openssl-unix": { - "baseline": "deprecated", - "port-version": 0 - }, - "openssl-uwp": { - "baseline": "deprecated", - "port-version": 0 - }, - "openssl-windows": { - "baseline": "deprecated", - "port-version": 0 - }, "opensubdiv": { "baseline": "3.5.0", "port-version": 2 }, "opentelemetry-cpp": { - "baseline": "1.16.1", + "baseline": "1.17.0", "port-version": 0 }, "opentelemetry-cpp-contrib-version": { @@ -6730,7 +6722,7 @@ }, "openvino": { "baseline": "2024.4.0", - "port-version": 0 + "port-version": 1 }, "openvpn3": { "baseline": "3.10", @@ -6781,8 +6773,8 @@ "port-version": 3 }, "osgearth": { - "baseline": "3.4", - "port-version": 3 + "baseline": "3.7", + "port-version": 0 }, "osmanip": { "baseline": "4.6.1", @@ -6805,8 +6797,8 @@ "port-version": 4 }, "pagmo2": { - "baseline": "2.19.0", - "port-version": 2 + "baseline": "2.19.1", + "port-version": 0 }, "paho-mqtt": { "baseline": "1.3.13", @@ -6821,12 +6813,12 @@ "port-version": 0 }, "pango": { - "baseline": "1.50.14", - "port-version": 4 + "baseline": "1.54.0", + "port-version": 0 }, "pangolin": { - "baseline": "0.8", - "port-version": 3 + "baseline": "0.9.2", + "port-version": 0 }, "pangomm": { "baseline": "2.50.1", @@ -6878,7 +6870,7 @@ }, "pcl": { "baseline": "1.14.1", - "port-version": 1 + "port-version": 2 }, "pcre": { "baseline": "8.45", @@ -6909,7 +6901,7 @@ "port-version": 0 }, "pegtl": { - "baseline": "3.2.7", + "baseline": "3.2.8", "port-version": 0 }, "pegtl-2": { @@ -6917,7 +6909,7 @@ "port-version": 3 }, "perfetto": { - "baseline": "47.0", + "baseline": "48.1", "port-version": 0 }, "pffft": { @@ -6961,8 +6953,8 @@ "port-version": 2 }, "pipewire": { - "baseline": "1.0.4", - "port-version": 3 + "baseline": "1.2.5", + "port-version": 0 }, "pistache": { "baseline": "2021-03-31", @@ -6981,7 +6973,7 @@ "port-version": 0 }, "plasma-wayland-protocols": { - "baseline": "1.8.0", + "baseline": "1.14.0", "port-version": 0 }, "platform-folders": { @@ -7116,6 +7108,10 @@ "baseline": "239", "port-version": 0 }, + "poselib": { + "baseline": "2.0.4", + "port-version": 0 + }, "ppconsul": { "baseline": "0.5", "port-version": 5 @@ -7149,8 +7145,8 @@ "port-version": 0 }, "proj": { - "baseline": "9.4.1", - "port-version": 2 + "baseline": "9.5.0", + "port-version": 0 }, "projectm-eval": { "baseline": "1.0.0", @@ -7189,7 +7185,7 @@ "port-version": 0 }, "proxygen": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "psimd": { @@ -7201,7 +7197,7 @@ "port-version": 1 }, "ptex": { - "baseline": "2.4.2", + "baseline": "2.4.3", "port-version": 0 }, "pthread": { @@ -7253,8 +7249,8 @@ "port-version": 7 }, "python3": { - "baseline": "3.11.8", - "port-version": 5 + "baseline": "3.11.10", + "port-version": 0 }, "qca": { "baseline": "2.3.7", @@ -7673,7 +7669,7 @@ "port-version": 0 }, "quantlib": { - "baseline": "1.35", + "baseline": "1.36", "port-version": 0 }, "quaternions": { @@ -7741,7 +7737,7 @@ "port-version": 0 }, "rapidcsv": { - "baseline": "8.83", + "baseline": "8.84", "port-version": 0 }, "rapidfuzz": { @@ -7837,7 +7833,7 @@ "port-version": 0 }, "redis-plus-plus": { - "baseline": "1.3.12", + "baseline": "1.3.13", "port-version": 0 }, "refl-cpp": { @@ -7857,8 +7853,8 @@ "port-version": 1 }, "reproc": { - "baseline": "14.2.4", - "port-version": 2 + "baseline": "14.2.5", + "port-version": 0 }, "rest-rpc": { "baseline": "0.12", @@ -7870,7 +7866,7 @@ }, "restc-cpp": { "baseline": "0.10.0", - "port-version": 3 + "port-version": 4 }, "restclient-cpp": { "baseline": "2022-02-09", @@ -7885,8 +7881,8 @@ "port-version": 0 }, "rhash": { - "baseline": "1.4.4", - "port-version": 1 + "baseline": "1.4.5", + "port-version": 0 }, "rhasheq": { "baseline": "2023-06-17", @@ -7909,7 +7905,7 @@ "port-version": 0 }, "rkcommon": { - "baseline": "1.10.0", + "baseline": "1.14.2", "port-version": 0 }, "rmlui": { @@ -7921,7 +7917,7 @@ "port-version": 1 }, "roaring": { - "baseline": "4.1.3", + "baseline": "4.2.1", "port-version": 0 }, "robin-hood-hashing": { @@ -7941,7 +7937,7 @@ "port-version": 0 }, "rocksdb": { - "baseline": "9.6.1", + "baseline": "9.7.2", "port-version": 0 }, "rpclib": { @@ -8037,7 +8033,7 @@ "port-version": 0 }, "s2n": { - "baseline": "1.4.16", + "baseline": "1.5.5", "port-version": 0 }, "safeint": { @@ -8309,7 +8305,7 @@ "port-version": 1 }, "simd": { - "baseline": "6.1.140", + "baseline": "6.1.142", "port-version": 0 }, "simde": { @@ -8321,7 +8317,7 @@ "port-version": 0 }, "simdutf": { - "baseline": "5.5.0", + "baseline": "5.6.0", "port-version": 0 }, "simonbrunel-qtpromise": { @@ -8354,7 +8350,7 @@ }, "skia": { "baseline": "129", - "port-version": 1 + "port-version": 2 }, "skyr-url": { "baseline": "1.13.0", @@ -8537,19 +8533,19 @@ "port-version": 4 }, "spirv-cross": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "spirv-headers": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "spirv-reflect": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "spirv-tools": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "spout2": { @@ -8709,7 +8705,7 @@ "port-version": 0 }, "superlu": { - "baseline": "6.0.1", + "baseline": "7.0.0", "port-version": 0 }, "swenson-sort": { @@ -8865,8 +8861,8 @@ "port-version": 2 }, "tiff": { - "baseline": "4.6.0", - "port-version": 5 + "baseline": "4.7.0", + "port-version": 0 }, "tinkerforge": { "baseline": "2.1.25", @@ -9008,6 +9004,10 @@ "baseline": "2019-10-14", "port-version": 1 }, + "tobias-loew-flags": { + "baseline": "2024-09-10", + "port-version": 0 + }, "toml11": { "baseline": "4.2.0", "port-version": 0 @@ -9054,7 +9054,7 @@ }, "triangle": { "baseline": "1.6", - "port-version": 3 + "port-version": 4 }, "triton": { "baseline": "2023-08-16", @@ -9157,7 +9157,7 @@ "port-version": 0 }, "upa-url": { - "baseline": "1.0.0", + "baseline": "1.0.1", "port-version": 0 }, "upb": { @@ -9289,7 +9289,7 @@ "port-version": 0 }, "vcpkg-get-python-packages": { - "baseline": "2024-01-24", + "baseline": "2024-09-29", "port-version": 0 }, "vcpkg-gfortran": { @@ -9405,7 +9405,7 @@ "port-version": 0 }, "volk": { - "baseline": "1.3.295", + "baseline": "1.3.296", "port-version": 0 }, "vowpal-wabbit": { @@ -9445,15 +9445,15 @@ "port-version": 0 }, "vulkan-headers": { - "baseline": "1.3.290.0", - "port-version": 1 + "baseline": "1.3.296.0", + "port-version": 0 }, "vulkan-hpp": { "baseline": "deprecated", "port-version": 0 }, "vulkan-loader": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "vulkan-memory-allocator": { @@ -9465,19 +9465,19 @@ "port-version": 0 }, "vulkan-sdk-components": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "vulkan-tools": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "vulkan-utility-libraries": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "vulkan-validationlayers": { - "baseline": "1.3.290.0", + "baseline": "1.3.296.0", "port-version": 0 }, "vvenc": { @@ -9485,8 +9485,8 @@ "port-version": 0 }, "vxl": { - "baseline": "2.0.2", - "port-version": 7 + "baseline": "3.5.0", + "port-version": 0 }, "wabt": { "baseline": "1.0.36", @@ -9497,7 +9497,7 @@ "port-version": 5 }, "wangle": { - "baseline": "2024.09.30.00", + "baseline": "2024.10.07.00", "port-version": 0 }, "wasmedge": { @@ -9889,7 +9889,7 @@ "port-version": 0 }, "zoe": { - "baseline": "3.1", + "baseline": "3.2", "port-version": 0 }, "zookeeper": { diff --git a/vcpkg/versions/d-/dpp.json b/vcpkg/versions/d-/dpp.json index 05a8f382d5..11230705c7 100644 --- a/vcpkg/versions/d-/dpp.json +++ b/vcpkg/versions/d-/dpp.json @@ -1,8 +1,8 @@ { "versions": [ { - "git-tree": "7543dc1ca437d9f26cb6754b9f60ff58901c0e2a", - "version": "10.0.32", + "git-tree": "58fffa3b78cf2a0c2e28b5abdd40931a4b0a5c40", + "version": "10.0.33", "port-version": 0 }, { From 0798b34e1be0952403d337099615066954ad35cf Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Sun, 20 Oct 2024 22:47:17 +0000 Subject: [PATCH 91/99] [skip ci] version bump --- include/dpp/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/dpp/version.h b/include/dpp/version.h index e94dc4af7b..38601074b4 100644 --- a/include/dpp/version.h +++ b/include/dpp/version.h @@ -22,9 +22,9 @@ #pragma once #ifndef DPP_VERSION_LONG -#define DPP_VERSION_LONG 0x00100033 -#define DPP_VERSION_SHORT 100033 -#define DPP_VERSION_TEXT "D++ 10.0.33 (13-Oct-2024)" +#define DPP_VERSION_LONG 0x00100034 +#define DPP_VERSION_SHORT 100034 +#define DPP_VERSION_TEXT "D++ 10.0.34 (20-Oct-2024)" #define DPP_VERSION_MAJOR ((DPP_VERSION_LONG & 0x00ff0000) >> 16) #define DPP_VERSION_MINOR ((DPP_VERSION_LONG & 0x0000ff00) >> 8) From 9c164911021efd01d24858461f23559e03e5ae4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:09:25 +0100 Subject: [PATCH 92/99] build(deps): bump ubuntu from `d4f6f70` to `99c3519` (#1296) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 28c70cdc00..b9ded8ca5f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:noble@sha256:d4f6f70979d0758d7a6f81e34a61195677f4f4fa576eaf808b79f17499fd93d1 +FROM ubuntu:noble@sha256:99c35190e22d294cdace2783ac55effc69d32896daaa265f0bbedbcde4fbe3e5 RUN apt-get update && apt-get install --no-install-recommends -y libssl-dev zlib1g-dev libopus-dev cmake pkg-config g++ gcc git make && apt-get clean && rm -rf /var/lib/apt/lists/* From f4627703c77dfbdd6d4deb9c5f34bc7b1dc1eb2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:09:53 +0100 Subject: [PATCH 93/99] build(deps): bump rui314/setup-mold from 0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 to b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e (#1297) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00579aefac..4b53759db9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: - name: Setup mold if: ${{ matrix.cfg.mold == 'yes' }} - uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 # v1 + uses: rui314/setup-mold@b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e # v1 - name: Add LLVM apt repository if: ${{ matrix.cfg.llvm-apt }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index dacca76652..2a04bdce38 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -58,7 +58,7 @@ jobs: # Prefix the list here with "+" to use these queries and those in the config file. - name: Setup mold - uses: rui314/setup-mold@0bf4f07ef9048ec62a45f9dbf2f098afa49695f0 + uses: rui314/setup-mold@b015f7e3f2938ad3a5ed6e5111a8c6c7c1d6db6e - name: Build run: cmake -B build -DDPP_NO_VCPKG=ON -DAVX_TYPE=AVX0 -DCMAKE_BUILD_TYPE=Release && cmake --build build -j4 From 8ea190fa91eb155e670737c065df24bc3c031978 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:10:15 +0100 Subject: [PATCH 94/99] build(deps): bump step-security/harden-runner from 2.8.1 to 2.10.1 (#1298) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql.yml | 2 +- .github/workflows/construct-vcpkg-info.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/documentation-check.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/gitguardian.yml | 2 +- .github/workflows/labeler.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/sitemap.yml | 2 +- .github/workflows/stale.yml | 2 +- .github/workflows/target-master.yml | 2 +- .github/workflows/test-docs-examples.yml | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b53759db9..43075732b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,7 +65,7 @@ jobs: - { arch: 'arm64', concurrency: 4, os: [self-hosted, linux, ARM64], package: g++-12, cpp: g++, version: 12, cmake-flags: '', cpack: 'yes', ctest: 'no', mold: 'yes' } steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit @@ -137,7 +137,7 @@ jobs: - { arch: 'arm64', concurrency: 3, os: macos-latest, cpp: clang++, version: 14, cmake-flags: '', xcode-version: '14.3.1' } steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit @@ -191,7 +191,7 @@ jobs: runs-on: ${{matrix.cfg.os}} steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit @@ -256,7 +256,7 @@ jobs: runs-on: ${{matrix.cfg.os}} steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2a04bdce38..3defeb76d4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/construct-vcpkg-info.yml b/.github/workflows/construct-vcpkg-info.yml index fb93c393b3..69f0c4a04c 100644 --- a/.github/workflows/construct-vcpkg-info.yml +++ b/.github/workflows/construct-vcpkg-info.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 59eea8f943..5c03af260a 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1ceb3da716..90b7dca5ce 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,7 @@ jobs: cancel-in-progress: false steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/documentation-check.yml b/.github/workflows/documentation-check.yml index b6b0f661dd..15c714a738 100644 --- a/.github/workflows/documentation-check.yml +++ b/.github/workflows/documentation-check.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 4a8757cb87..06e05a490c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index cce9cb457f..0058310d5f 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -14,7 +14,7 @@ jobs: cancel-in-progress: true steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index d4802a85c7..c4cf52f566 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index bd519b29f7..5d0609f348 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/sitemap.yml b/.github/workflows/sitemap.yml index 6f49980d2b..cfe156e5e1 100644 --- a/.github/workflows/sitemap.yml +++ b/.github/workflows/sitemap.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 2e6162ab76..fc5c9fb328 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/target-master.yml b/.github/workflows/target-master.yml index 6eed961974..7c6c7c2d82 100644 --- a/.github/workflows/target-master.yml +++ b/.github/workflows/target-master.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit diff --git a/.github/workflows/test-docs-examples.yml b/.github/workflows/test-docs-examples.yml index 648916d6b3..aa5cf63fd4 100644 --- a/.github/workflows/test-docs-examples.yml +++ b/.github/workflows/test-docs-examples.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 with: egress-policy: audit From c8b5e5bac3cec1fcc7946bf4bca74db07a384e07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:10:38 +0100 Subject: [PATCH 95/99] build(deps): bump doxygen-awesome-css from `4593c19` to `af1d903` (#1299) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- doxygen-awesome-css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doxygen-awesome-css b/doxygen-awesome-css index 4593c19803..af1d9030b3 160000 --- a/doxygen-awesome-css +++ b/doxygen-awesome-css @@ -1 +1 @@ -Subproject commit 4593c198030b6e5019aae4d9c2eeb7497f02dbf8 +Subproject commit af1d9030b3ffa7b483fa9997a7272fb12af6af4c From 81369567f9f6dffa499bef87381bd2220a03043e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:11:04 +0100 Subject: [PATCH 96/99] build(deps): bump actions/checkout from 4.2.0 to 4.2.1 (#1300) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/codeql.yml | 2 +- .github/workflows/construct-vcpkg-info.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/documentation-check.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/gitguardian.yml | 2 +- .github/workflows/scorecard.yml | 2 +- .github/workflows/test-docs-examples.yml | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43075732b5..4c9293d241 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Setup mold if: ${{ matrix.cfg.mold == 'yes' }} @@ -142,7 +142,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Update Xcode uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 @@ -196,7 +196,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: path: main @@ -261,7 +261,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Install Packages run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt update && sudo apt-get install -y cmake rpm diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3defeb76d4..56607b609b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,7 +46,7 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/construct-vcpkg-info.yml b/.github/workflows/construct-vcpkg-info.yml index 69f0c4a04c..be0ddf44b3 100644 --- a/.github/workflows/construct-vcpkg-info.yml +++ b/.github/workflows/construct-vcpkg-info.yml @@ -25,7 +25,7 @@ jobs: php-version: '8.1' - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: submodules: recursive diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 5c03af260a..7b0990bcf5 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -22,6 +22,6 @@ jobs: egress-policy: audit - name: 'Checkout Repository' - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: 'Dependency Review' uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 diff --git a/.github/workflows/documentation-check.yml b/.github/workflows/documentation-check.yml index 15c714a738..6976497ad0 100644 --- a/.github/workflows/documentation-check.yml +++ b/.github/workflows/documentation-check.yml @@ -27,7 +27,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - name: Check docs spelling run: npx -y cspell lint --language-id=cpp --no-progress --no-summary --show-context --show-suggestions --relative --color docpages/*.md include/dpp/*.h diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 06e05a490c..ca694b0bd1 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -35,7 +35,7 @@ jobs: php-version: '8.0' - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: submodules: recursive diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index 0058310d5f..1ceac058e0 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -19,7 +19,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: fetch-depth: 0 # fetch all history so multiple commits can be scanned - name: GitGuardian scan diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 5d0609f348..9a86a90d72 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -37,7 +37,7 @@ jobs: egress-policy: audit - name: "Checkout code" - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: persist-credentials: false diff --git a/.github/workflows/test-docs-examples.yml b/.github/workflows/test-docs-examples.yml index aa5cf63fd4..1be005e42c 100644 --- a/.github/workflows/test-docs-examples.yml +++ b/.github/workflows/test-docs-examples.yml @@ -30,7 +30,7 @@ jobs: egress-policy: audit - name: Checkout D++ - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 with: submodules: recursive From 351b352bd24d44d9bb9136b982628282686be952 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:11:34 +0100 Subject: [PATCH 97/99] build(deps): bump docker/setup-buildx-action from 3.6.1 to 3.7.1 (#1301) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 90b7dca5ce..4f69516150 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -31,7 +31,7 @@ jobs: uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - name: Login to DockerHub uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 From 950e86ad2dea3bcd9a6e05cba718e965253d355e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:12:01 +0100 Subject: [PATCH 98/99] build(deps): bump actions/upload-artifact from 4.3.4 to 4.4.3 (#1302) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/scorecard.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c9293d241..eb9c2a65ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,14 +111,14 @@ jobs: - name: Upload Binary (DEB) if: ${{ matrix.cfg.cpack == 'yes' }} - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: "libdpp - Debian Package ${{matrix.cfg.arch}}" path: '${{github.workspace}}/build/*.deb' - name: Upload Binary (RPM) if: ${{ matrix.cfg.cpack == 'yes' }} - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: "libdpp - RPM Package ${{matrix.cfg.arch}}" path: '${{github.workspace}}/build/*.rpm' @@ -234,7 +234,7 @@ jobs: - name: Upload Binary if: ${{ matrix.cfg.upload }} - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: "libdpp - Windows ${{matrix.cfg.name}}-${{matrix.cfg.config}}-vs${{matrix.cfg.vs}}" path: '${{github.workspace}}/main/build/*.zip' @@ -276,13 +276,13 @@ jobs: run: cd build && sudo cpack --verbose || cat /home/runner/work/DPP/DPP/build/_CPack_Packages/Linux/DEB/PreinstallOutput.log - name: Upload Binaries (DEB) - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: "libdpp - Debian Package ${{matrix.cfg.name}}" path: "${{github.workspace}}/build/*.deb" - name: Upload Binaries (RPM) - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: "libdpp - RPM Package ${{matrix.cfg.name}}" path: "${{github.workspace}}/build/*.rpm" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 9a86a90d72..80afe1ff49 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -64,7 +64,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: SARIF file path: results.sarif From 4906105c801e79baab16f591295cfd8771b4c398 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:12:32 +0100 Subject: [PATCH 99/99] build(deps): bump GitGuardian/ggshield-action from 1.32.0 to 1.32.2 (#1303) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gitguardian.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index 1ceac058e0..7542e71005 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -23,7 +23,7 @@ jobs: with: fetch-depth: 0 # fetch all history so multiple commits can be scanned - name: GitGuardian scan - uses: GitGuardian/ggshield-action@53910b10ce6646fb7c6e353f55f26ed96d0cff1b # master + uses: GitGuardian/ggshield-action@0cb2e309a0ce2cd43141dc998c28d9b225a7a1fe # master env: GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} GITHUB_PUSH_BASE_SHA: ${{ github.event.base }}

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�Q3g-H+!0S@;8U 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