Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ValidationHelpers.hpp
1#pragma once
2
3#include <boost/json/array.hpp>
4#include <boost/json/object.hpp>
5#include <boost/json/value.hpp>
6
7#include <concepts>
8#include <cstdint>
9#include <limits>
10#include <string>
11#include <type_traits>
12
13namespace rpc::validation {
14namespace impl {
15
16template <std::unsigned_integral Expected>
17void
18clampAs(boost::json::value& value)
19{
20 if (value.is_uint64()) {
21 auto const valueUint = value.as_uint64();
22 if (valueUint > static_cast<uint64_t>(std::numeric_limits<Expected>::max()))
23 value = std::numeric_limits<Expected>::max();
24 } else if (value.is_int64()) {
25 auto const valueInt = value.as_int64();
26 if (valueInt > static_cast<int64_t>(std::numeric_limits<Expected>::max()))
27 value = std::numeric_limits<Expected>::max();
28 }
29}
30
31template <std::signed_integral Expected>
32void
33clampAs(boost::json::value& value)
34{
35 if (value.is_uint64()) {
36 auto const valueUint = value.as_uint64();
37 if (valueUint > static_cast<uint64_t>(std::numeric_limits<Expected>::max()))
38 value = std::numeric_limits<Expected>::max();
39 } else if (value.is_int64()) {
40 auto const valueInt = value.as_int64();
41 if (valueInt > static_cast<int64_t>(std::numeric_limits<Expected>::max())) {
42 value = std::numeric_limits<Expected>::max();
43 } else if (valueInt < static_cast<int64_t>(std::numeric_limits<Expected>::min())) {
44 value = std::numeric_limits<Expected>::min();
45 }
46 }
47}
48
49} // namespace impl
50
58template <typename Expected>
59[[nodiscard]] bool
60checkType(boost::json::value const& value)
61{
62 auto hasError = false;
63 if constexpr (std::is_same_v<Expected, bool>) {
64 if (not value.is_bool())
65 hasError = true;
66 } else if constexpr (std::is_same_v<Expected, std::string>) {
67 if (not value.is_string())
68 hasError = true;
69 } else if constexpr (std::is_same_v<Expected, double> or std::is_same_v<Expected, float>) {
70 if (not value.is_double())
71 hasError = true;
72 } else if constexpr (std::is_same_v<Expected, boost::json::array>) {
73 if (not value.is_array())
74 hasError = true;
75 } else if constexpr (std::is_same_v<Expected, boost::json::object>) {
76 if (not value.is_object())
77 hasError = true;
78 } else if constexpr (
79 std::is_convertible_v<Expected, uint64_t> or std::is_convertible_v<Expected, int64_t>
80 ) {
81 if (not value.is_int64() && not value.is_uint64())
82 hasError = true;
83 // if the type specified is unsigned, it should not be negative
84 if constexpr (std::is_unsigned_v<Expected>) {
85 if (value.is_int64() and value.as_int64() < 0)
86 hasError = true;
87 }
88 }
89
90 return not hasError;
91}
92
104template <typename Expected>
105[[nodiscard]] bool
106checkTypeAndClamp(boost::json::value& value)
107{
108 if (not checkType<Expected>(value))
109 return false; // fails basic type check
110
111 if constexpr (std::is_integral_v<Expected> and not std::is_same_v<Expected, bool>)
112 impl::clampAs<Expected>(value);
113
114 return true;
115}
116
117} // namespace rpc::validation