2021-08-06 20:00:29 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <nlohmann/json.hpp>
|
2023-04-13 15:50:13 +02:00
|
|
|
#include <string_view>
|
2021-08-19 05:43:26 +02:00
|
|
|
#include <unordered_set>
|
2021-08-06 20:00:29 +02:00
|
|
|
|
2023-04-13 15:50:13 +02:00
|
|
|
#include "crypto/crypto.h"
|
|
|
|
#include "ringct/rctTypes.h"
|
|
|
|
|
2021-08-06 20:00:29 +02:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2022-12-21 02:34:04 +01:00
|
|
|
namespace tools {
|
2021-08-06 20:00:29 +02:00
|
|
|
|
2023-04-13 15:50:13 +02:00
|
|
|
// Binary types that we support for rpc input/output. For json, these must be specified as hex or
|
|
|
|
// base64; for bt-encoded requests these can be accepted as binary, hex, or base64.
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary = false;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<crypto::hash> = true;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<crypto::public_key> = true;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<crypto::ed25519_public_key> = true;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<crypto::x25519_public_key> = true;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<crypto::key_image> = true;
|
|
|
|
template <>
|
|
|
|
inline constexpr bool json_is_binary<rct::key> = true;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary_container = false;
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary_container<std::vector<T>> = json_is_binary<T>;
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary_container<std::unordered_set<T>> = json_is_binary<T>;
|
|
|
|
|
|
|
|
// De-referencing wrappers around the above:
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary<const T&> = json_is_binary<T>;
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary<T&&> = json_is_binary<T>;
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary_container<const T&> = json_is_binary_container<T>;
|
|
|
|
template <typename T>
|
|
|
|
inline constexpr bool json_is_binary_container<T&&> = json_is_binary_container<T>;
|
|
|
|
|
|
|
|
void load_binary_parameter_impl(
|
|
|
|
std::string_view bytes, size_t raw_size, bool allow_raw, uint8_t* val_data);
|
|
|
|
|
|
|
|
// Loads a binary value from a string_view which may contain hex, base64, and (optionally) raw
|
|
|
|
// bytes.
|
|
|
|
template <typename T, typename = std::enable_if_t<json_is_binary<T>>>
|
|
|
|
void load_binary_parameter(std::string_view bytes, bool allow_raw, T& val) {
|
2021-08-06 20:00:29 +02:00
|
|
|
load_binary_parameter_impl(bytes, sizeof(T), allow_raw, reinterpret_cast<uint8_t*>(&val));
|
2023-04-13 15:50:13 +02:00
|
|
|
}
|
2021-08-06 20:00:29 +02:00
|
|
|
|
2023-04-13 15:50:13 +02:00
|
|
|
// Wrapper around a nlohmann::json that assigns a binary value either as binary (for bt-encoding);
|
|
|
|
// or as hex or base64 (for json-encoding).
|
|
|
|
class json_binary_proxy {
|
|
|
|
public:
|
2021-08-06 20:00:29 +02:00
|
|
|
nlohmann::json& e;
|
|
|
|
enum class fmt { bt, hex, base64 } format;
|
2023-04-13 15:50:13 +02:00
|
|
|
explicit json_binary_proxy(nlohmann::json& elem, fmt format) : e{elem}, format{format} {}
|
2021-08-06 20:00:29 +02:00
|
|
|
json_binary_proxy() = delete;
|
|
|
|
|
|
|
|
json_binary_proxy(const json_binary_proxy&) = default;
|
|
|
|
json_binary_proxy(json_binary_proxy&&) = default;
|
|
|
|
|
|
|
|
/// Dereferencing a proxy element accesses the underlying nlohmann::json
|
|
|
|
nlohmann::json& operator*() { return e; }
|
|
|
|
nlohmann::json* operator->() { return &e; }
|
|
|
|
|
|
|
|
/// Descends into the json object, returning a new binary value proxy around the child element.
|
|
|
|
template <typename T>
|
|
|
|
json_binary_proxy operator[](T&& key) {
|
2023-04-13 15:50:13 +02:00
|
|
|
return json_binary_proxy{e[std::forward<T>(key)], format};
|
2021-08-06 20:00:29 +02:00
|
|
|
}
|
|
|
|
|
2021-08-18 16:45:49 +02:00
|
|
|
/// Returns a binary value proxy around the first/last element (requires an underlying list)
|
|
|
|
json_binary_proxy front() { return json_binary_proxy{e.front(), format}; }
|
|
|
|
json_binary_proxy back() { return json_binary_proxy{e.back(), format}; }
|
|
|
|
|
2021-08-06 20:00:29 +02:00
|
|
|
/// Assigns binary data from a string_view/string/etc.
|
|
|
|
nlohmann::json& operator=(std::string_view binary_data);
|
|
|
|
|
|
|
|
/// Assigns binary data from a string_view over a 1-byte, non-char type (e.g. unsigned char or
|
|
|
|
/// uint8_t).
|
2023-04-13 15:50:13 +02:00
|
|
|
template <
|
|
|
|
typename Char,
|
|
|
|
std::enable_if_t<sizeof(Char) == 1 && !std::is_same_v<Char, char>, int> = 0>
|
2021-08-06 20:00:29 +02:00
|
|
|
nlohmann::json& operator=(std::basic_string_view<Char> binary_data) {
|
2023-04-13 15:50:13 +02:00
|
|
|
return *this = std::string_view{
|
|
|
|
reinterpret_cast<const char*>(binary_data.data()), binary_data.size()};
|
2021-08-06 20:00:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Takes a trivial, no-padding data structure (e.g. a crypto::hash) as the value and dumps its
|
|
|
|
/// contents as the binary value.
|
2022-12-21 02:34:04 +01:00
|
|
|
template <typename T, std::enable_if_t<json_is_binary<T>, int> = 0>
|
2021-08-06 20:00:29 +02:00
|
|
|
nlohmann::json& operator=(const T& val) {
|
2023-04-13 15:50:13 +02:00
|
|
|
return *this = std::string_view{reinterpret_cast<const char*>(&val), sizeof(val)};
|
2021-08-06 20:00:29 +02:00
|
|
|
}
|
2021-08-13 20:16:10 +02:00
|
|
|
|
|
|
|
/// Takes a vector of some json_binary_proxy-assignable type and builds an array by assigning
|
|
|
|
/// each one into a new array of binary values.
|
2022-12-21 02:34:04 +01:00
|
|
|
template <typename T, std::enable_if_t<json_is_binary_container<T>, int> = 0>
|
2021-08-19 05:43:26 +02:00
|
|
|
nlohmann::json& operator=(const T& vals) {
|
2023-04-13 15:50:13 +02:00
|
|
|
auto a = nlohmann::json::array();
|
|
|
|
for (auto& val : vals)
|
|
|
|
json_binary_proxy{a.emplace_back(), format} = val;
|
|
|
|
return e = std::move(a);
|
|
|
|
}
|
|
|
|
/// Emplaces a new nlohman::json to the end of an underlying list and returns a
|
|
|
|
/// json_binary_proxy wrapping it.
|
|
|
|
///
|
|
|
|
/// Example:
|
|
|
|
///
|
|
|
|
/// auto child = wrappedelem.emplace_back({"key1": 1}, {"key2": 2});
|
|
|
|
/// child["binary-key"] = some_binary_thing;
|
|
|
|
template <typename... Args>
|
|
|
|
json_binary_proxy emplace_back(Args&&... args) {
|
|
|
|
return json_binary_proxy{e.emplace_back(std::forward<Args>(args)...), format};
|
2021-08-13 20:16:10 +02:00
|
|
|
}
|
2021-08-06 20:00:29 +02:00
|
|
|
|
2023-04-13 15:50:13 +02:00
|
|
|
/// Adds an element to an underlying list, then copies or moves the given argument onto it via
|
|
|
|
/// json_binary_proxy assignment.
|
|
|
|
template <typename T>
|
|
|
|
void push_back(T&& val) {
|
|
|
|
emplace_back() = std::forward<T>(val);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace tools
|
2021-08-06 20:00:29 +02:00
|
|
|
|
|
|
|
// Specializations of binary types for deserialization; when receiving these from json we expect
|
|
|
|
// them encoded in hex or base64. These may *not* be used for serialization, and will throw if so
|
|
|
|
// invoked; for serialization you need to use RPC_COMMAND::response_hex (or _b64) instead.
|
|
|
|
namespace nlohmann {
|
2023-04-13 15:50:13 +02:00
|
|
|
template <typename T>
|
|
|
|
struct adl_serializer<T, std::enable_if_t<tools::json_is_binary<T>>> {
|
2021-08-06 20:00:29 +02:00
|
|
|
static_assert(std::is_trivially_copyable_v<T> && std::has_unique_object_representations_v<T>);
|
|
|
|
|
|
|
|
static void to_json(json& j, const T&) {
|
2023-04-13 15:50:13 +02:00
|
|
|
throw std::logic_error{"Internal error: binary types are not directly serializable"};
|
2021-08-06 20:00:29 +02:00
|
|
|
}
|
|
|
|
static void from_json(const json& j, T& val) {
|
2023-04-13 15:50:13 +02:00
|
|
|
tools::load_binary_parameter(j.get<std::string_view>(), false /*no raw*/, val);
|
2021-08-06 20:00:29 +02:00
|
|
|
}
|
2023-04-13 15:50:13 +02:00
|
|
|
};
|
|
|
|
} // namespace nlohmann
|