| #include "json_utils.h" | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <optional> | |
| #include <string> | |
| #include <string_view> | |
| #include "absl/log/log.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/numbers.h" | |
| #include "absl/strings/str_cat.h" | |
| #include <nlohmann/json.hpp> | |
| namespace milotic::authz { | |
| namespace { | |
| template <typename ReturnType> | |
| const ReturnType* GetValueAsType(const nlohmann::json& root, | |
| std::string_view key, | |
| [[maybe_unused]] std::string_view type_name) { | |
| if (root.is_discarded()) { | |
| LOG(WARNING) << "Invalid JSON object"; | |
| return nullptr; | |
| } | |
| auto it = root.find(key); | |
| if (it == root.end()) { | |
| return nullptr; | |
| } | |
| if constexpr (std::is_same_v<ReturnType, nlohmann::json>) { | |
| return &(*it); | |
| } else { | |
| return it->get_ptr<const ReturnType*>(); | |
| } | |
| } | |
| template <typename ReturnType> | |
| ReturnType* GetValueAsMutableType(nlohmann::json& root, std::string_view key, | |
| [[maybe_unused]] std::string_view type_name) { | |
| if (root.is_discarded()) { | |
| LOG(WARNING) << "Invalid JSON object"; | |
| return nullptr; | |
| } | |
| auto it = root.find(key); | |
| if (it == root.end()) { | |
| return nullptr; | |
| } | |
| if constexpr (std::is_same_v<ReturnType, nlohmann::json>) { | |
| return &(*it); | |
| } else { | |
| return it->get_ptr<ReturnType*>(); | |
| } | |
| } | |
| } // namespace | |
| const std::string* GetValueAsString(const nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsType<std::string>(root, key, "string"); | |
| } | |
| const std::string* GetValueAsString( | |
| const nlohmann::json& root, const nlohmann::json::json_pointer& pointer) { | |
| if (!root.contains(pointer)) { | |
| return nullptr; | |
| } | |
| return root[pointer].get_ptr<const std::string*>(); | |
| } | |
| const nlohmann::json* GetValueAsJson(const nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsType<nlohmann::json>(root, key, "object"); | |
| } | |
| absl::StatusOr<nlohmann::json> CheckAndGetValueAsJson( | |
| const nlohmann::json& root, const nlohmann::json::json_pointer& pointer) { | |
| if (!root.contains(pointer)) { | |
| return absl::NotFoundError( | |
| "Could not find pointer: " + pointer.to_string() + | |
| " in json: " + root.dump()); | |
| } | |
| return root[pointer]; | |
| } | |
| const nlohmann::json::array_t* GetValueAsArray(const nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsType<nlohmann::json::array_t>(root, key, "array"); | |
| } | |
| nlohmann::json::array_t* GetValueAsMutableArray(nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsMutableType<nlohmann::json::array_t>(root, key, "array"); | |
| } | |
| const double* GetValueAsDouble(const nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsType<nlohmann::json::number_float_t>(root, key, "number"); | |
| } | |
| const int64_t* GetValueAsInt(const nlohmann::json& root, std::string_view key) { | |
| return GetValueAsType<nlohmann::json::number_integer_t>(root, key, "number"); | |
| } | |
| const bool* GetValueAsBool(const nlohmann::json& root, std::string_view key) { | |
| return GetValueAsType<nlohmann::json::boolean_t>(root, key, "boolean"); | |
| } | |
| const uint64_t* GetValueAsUint(const nlohmann::json& root, | |
| std::string_view key) { | |
| return GetValueAsType<nlohmann::json::number_unsigned_t>(root, key, "number"); | |
| } | |
| // The following functions are used to parse from json where the type may vary | |
| // and conversion is accepted. Return a value directly since a pointer cannot be | |
| // made to the temporary value after being converted to desired type. | |
| std::optional<uint64_t> GetValueAsUintFromStringOrInteger( | |
| const nlohmann::json& root, std::string_view key) { | |
| const nlohmann::json::number_unsigned_t* unsigned_ptr = | |
| GetValueAsType<nlohmann::json::number_unsigned_t>(root, key, "number"); | |
| if (unsigned_ptr != nullptr) { | |
| return *unsigned_ptr; | |
| } | |
| const std::string* string_ptr = | |
| GetValueAsType<std::string>(root, key, "string"); | |
| if (string_ptr == nullptr) { | |
| LOG(INFO) << absl::StrCat("Invalid json: ", key, " field does not exist ", | |
| root.dump()); | |
| return std::nullopt; | |
| } | |
| uint64_t unsigned_value; | |
| bool result; | |
| result = absl::SimpleAtoi(*string_ptr, &unsigned_value); | |
| if (!result) { | |
| LOG(INFO) << absl::StrCat("Invalid json: Failed to convert value at ", key, | |
| " to unsigned value: ", root.dump()); | |
| return std::nullopt; | |
| } | |
| LOG(INFO) << "Successfully converted string to unsigned value: " | |
| << unsigned_value; | |
| return unsigned_value; | |
| } | |
| std::optional<double> GetValueAsDoubleFromFloatOrInteger( | |
| const nlohmann::json& root, std::string_view key) { | |
| const double* double_ptr = | |
| GetValueAsType<nlohmann::json::number_float_t>(root, key, "number"); | |
| if (double_ptr != nullptr) { | |
| return *double_ptr; | |
| } | |
| const nlohmann::json::number_integer_t* int_ptr = | |
| GetValueAsType<nlohmann::json::number_integer_t>(root, key, "number"); | |
| if (int_ptr != nullptr) { | |
| return static_cast<double>(*int_ptr); | |
| } | |
| const nlohmann::json::number_unsigned_t* unsigned_ptr = | |
| GetValueAsType<nlohmann::json::number_unsigned_t>(root, key, "number"); | |
| if (unsigned_ptr != nullptr) { | |
| return static_cast<double>(*unsigned_ptr); | |
| } | |
| LOG(INFO) << absl::StrCat("Invalid json: Failed to convert value at ", key, | |
| " to double ", root.dump()); | |
| return std::nullopt; | |
| } | |
| const std::string* GetValueAsStringFromArray( | |
| const nlohmann::json::array_t& array, std::size_t index) { | |
| if (index >= array.size()) { | |
| LOG(INFO) << absl::StrCat("Invalid index: Index ", index, | |
| " is out of range for array of size ", | |
| array.size()); | |
| return nullptr; | |
| } | |
| return array[index].get_ptr<const std::string*>(); | |
| } | |
| } // namespace milotic::authz |