Files
DiscordBot/libdave/include/dave/dave_interfaces.h
T
2026-08-21 15:52:36 +02:00

225 lines
8.2 KiB
C++

#pragma once
#include <functional>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <map>
#include <variant>
#include <chrono>
#include <vector>
#include <dave/array_view.h>
#include <dave/dave.h>
#include <dave/version.h>
namespace mlspp {
namespace bytes_ns {
struct bytes;
}; // namespace bytes_ns
struct SignaturePrivateKey;
} // namespace mlspp
namespace discord {
namespace dave {
using EncryptorStats = DAVEEncryptorStats;
using DecryptorStats = DAVEDecryptorStats;
using KeyGeneration = uint32_t;
using EncryptionKey = ::mlspp::bytes_ns::bytes;
class MlsKeyRatchet;
enum MediaType : uint8_t { Audio, Video };
enum Codec : uint8_t { Unknown, Opus, VP8, VP9, H264, H265, AV1 };
enum LoggingSeverity {
LS_VERBOSE,
LS_INFO,
LS_WARNING,
LS_ERROR,
LS_NONE,
};
// Returned in std::variant when a message is hard-rejected and should trigger a reset
struct failed_t {};
// Returned in std::variant when a message is soft-rejected and should not trigger a reset
struct ignored_t {};
// Map of ID-key pairs.
// In ProcessCommit, this lists IDs whose keys have been added, changed, or removed;
// an empty value value means a key was removed.
using RosterMap = std::map<uint64_t, std::vector<uint8_t>>;
// Return type for functions producing RosterMap or hard or soft failures
using RosterVariant = std::variant<failed_t, ignored_t, RosterMap>;
constexpr auto kDefaultTransitionDuration = std::chrono::seconds(10);
class IKeyRatchet {
public:
virtual ~IKeyRatchet() noexcept = default;
virtual EncryptionKey GetKey(KeyGeneration generation) noexcept = 0;
virtual void DeleteKey(KeyGeneration generation) noexcept = 0;
};
namespace mls {
#if defined(__ANDROID__)
typedef JNIEnv* KeyPairContextType;
#else
typedef const char* KeyPairContextType;
#endif
class ISession {
public:
virtual ~ISession() noexcept = default;
virtual void Init(ProtocolVersion version,
uint64_t groupId,
std::string const& selfUserId,
std::shared_ptr<::mlspp::SignaturePrivateKey>& transientKey) noexcept = 0;
virtual void Reset() noexcept = 0;
virtual void SetProtocolVersion(ProtocolVersion version) noexcept = 0;
virtual ProtocolVersion GetProtocolVersion() const noexcept = 0;
virtual std::vector<uint8_t> GetLastEpochAuthenticator() const noexcept = 0;
virtual void SetExternalSender(std::vector<uint8_t> const& externalSenderPackage) noexcept = 0;
virtual std::optional<std::vector<uint8_t>> ProcessProposals(
std::vector<uint8_t> proposals,
std::set<std::string> const& recognizedUserIDs) noexcept = 0;
virtual RosterVariant ProcessCommit(std::vector<uint8_t> commit) noexcept = 0;
virtual std::optional<RosterMap> ProcessWelcome(
std::vector<uint8_t> welcome,
std::set<std::string> const& recognizedUserIDs) noexcept = 0;
virtual std::vector<uint8_t> GetMarshalledKeyPackage() noexcept = 0;
virtual std::unique_ptr<IKeyRatchet> GetKeyRatchet(
std::string const& userId) const noexcept = 0;
using PairwiseFingerprintCallback = std::function<void(std::vector<uint8_t> const&)>;
virtual void GetPairwiseFingerprint(uint16_t version,
std::string const& userId,
PairwiseFingerprintCallback callback) const noexcept = 0;
};
using MLSFailureCallback = std::function<void(std::string const&, std::string const&)>;
std::unique_ptr<ISession> CreateSession(KeyPairContextType context,
std::string authSessionId,
MLSFailureCallback callback) noexcept;
} // namespace mls
class IEncryptor {
public:
enum ResultCode {
Success,
EncryptionFailure,
MissingKeyRatchet,
MissingCryptor,
TooManyAttempts,
};
virtual ~IEncryptor() = default;
virtual void SetKeyRatchet(std::unique_ptr<IKeyRatchet> keyRatchet) = 0;
virtual void SetPassthroughMode(bool passthroughMode) = 0;
virtual bool HasKeyRatchet() const = 0;
virtual bool IsPassthroughMode() const = 0;
virtual void AssignSsrcToCodec(uint32_t ssrc, Codec codecType) = 0;
virtual Codec CodecForSsrc(uint32_t ssrc) = 0;
virtual ResultCode Encrypt(MediaType mediaType,
uint32_t ssrc,
ArrayView<const uint8_t> frame,
ArrayView<uint8_t> encryptedFrame,
size_t* bytesWritten) = 0;
virtual size_t GetMaxCiphertextByteSize(MediaType mediaType, size_t frameSize) = 0;
virtual EncryptorStats GetStats(MediaType mediaType) const = 0;
using ProtocolVersionChangedCallback = std::function<void()>;
virtual void SetProtocolVersionChangedCallback(ProtocolVersionChangedCallback callback) = 0;
virtual ProtocolVersion GetProtocolVersion() const = 0;
};
std::unique_ptr<IEncryptor> CreateEncryptor();
class IDecryptor {
public:
using Duration = std::chrono::seconds;
enum ResultCode {
Success,
DecryptionFailure,
MissingKeyRatchet,
InvalidNonce,
MissingCryptor,
};
virtual ~IDecryptor() = default;
virtual void TransitionToKeyRatchet(std::unique_ptr<IKeyRatchet> keyRatchet,
Duration transitionExpiry = kDefaultTransitionDuration) = 0;
virtual void TransitionToPassthroughMode(
bool passthroughMode,
Duration transitionExpiry = kDefaultTransitionDuration) = 0;
virtual ResultCode Decrypt(MediaType mediaType,
ArrayView<const uint8_t> encryptedFrame,
ArrayView<uint8_t> frame,
size_t* bytesWritten) = 0;
virtual size_t GetMaxPlaintextByteSize(MediaType mediaType, size_t encryptedFrameSize) = 0;
virtual DecryptorStats GetStats(MediaType mediaType) const = 0;
};
std::unique_ptr<IDecryptor> CreateDecryptor();
static_assert(DAVE_CODEC_UNKNOWN == static_cast<int>(Codec::Unknown));
static_assert(DAVE_CODEC_OPUS == static_cast<int>(Codec::Opus));
static_assert(DAVE_CODEC_VP8 == static_cast<int>(Codec::VP8));
static_assert(DAVE_CODEC_VP9 == static_cast<int>(Codec::VP9));
static_assert(DAVE_CODEC_H264 == static_cast<int>(Codec::H264));
static_assert(DAVE_CODEC_H265 == static_cast<int>(Codec::H265));
static_assert(DAVE_CODEC_AV1 == static_cast<int>(Codec::AV1));
static_assert(DAVE_MEDIA_TYPE_AUDIO == static_cast<int>(MediaType::Audio));
static_assert(DAVE_MEDIA_TYPE_VIDEO == static_cast<int>(MediaType::Video));
static_assert(DAVE_ENCRYPTOR_RESULT_CODE_SUCCESS == static_cast<int>(IEncryptor::Success));
static_assert(DAVE_ENCRYPTOR_RESULT_CODE_ENCRYPTION_FAILURE ==
static_cast<int>(IEncryptor::EncryptionFailure));
static_assert(DAVE_ENCRYPTOR_RESULT_CODE_MISSING_KEY_RATCHET ==
static_cast<int>(IEncryptor::MissingKeyRatchet));
static_assert(DAVE_ENCRYPTOR_RESULT_CODE_MISSING_CRYPTOR ==
static_cast<int>(IEncryptor::MissingCryptor));
static_assert(DAVE_ENCRYPTOR_RESULT_CODE_TOO_MANY_ATTEMPTS ==
static_cast<int>(IEncryptor::TooManyAttempts));
static_assert(DAVE_DECRYPTOR_RESULT_CODE_SUCCESS == static_cast<int>(IDecryptor::Success));
static_assert(DAVE_DECRYPTOR_RESULT_CODE_DECRYPTION_FAILURE ==
static_cast<int>(IDecryptor::DecryptionFailure));
static_assert(DAVE_DECRYPTOR_RESULT_CODE_MISSING_KEY_RATCHET ==
static_cast<int>(IDecryptor::MissingKeyRatchet));
static_assert(DAVE_DECRYPTOR_RESULT_CODE_INVALID_NONCE ==
static_cast<int>(IDecryptor::InvalidNonce));
static_assert(DAVE_DECRYPTOR_RESULT_CODE_MISSING_CRYPTOR ==
static_cast<int>(IDecryptor::MissingCryptor));
static_assert(DAVE_LOGGING_SEVERITY_VERBOSE == static_cast<int>(LoggingSeverity::LS_VERBOSE));
static_assert(DAVE_LOGGING_SEVERITY_INFO == static_cast<int>(LoggingSeverity::LS_INFO));
static_assert(DAVE_LOGGING_SEVERITY_WARNING == static_cast<int>(LoggingSeverity::LS_WARNING));
static_assert(DAVE_LOGGING_SEVERITY_ERROR == static_cast<int>(LoggingSeverity::LS_ERROR));
static_assert(DAVE_LOGGING_SEVERITY_NONE == static_cast<int>(LoggingSeverity::LS_NONE));
} // namespace dave
} // namespace discord