Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Validators.hpp
1#pragma once
2
3#include "rpc/Errors.hpp"
4#include "rpc/common/Types.hpp"
5#include "rpc/common/ValidationHelpers.hpp"
6
7#include <boost/json/array.hpp>
8#include <boost/json/object.hpp>
9#include <boost/json/value.hpp>
10#include <fmt/format.h>
11#include <xrpl/basics/base_uint.h>
12#include <xrpl/protocol/ErrorCodes.h>
13
14#include <concepts>
15#include <ctime>
16#include <functional>
17#include <initializer_list>
18#include <string>
19#include <string_view>
20#include <utility>
21#include <vector>
22
23namespace rpc::validation {
24
28struct Required final {
36 [[nodiscard]] static MaybeError
37 verify(boost::json::value const& value, std::string_view key);
38};
39
46template <typename... T>
48
53template <typename T>
54class NotSupported<T> final {
55 T value_;
56
57public:
63 NotSupported(T val) : value_(val)
64 {
65 }
66
74 [[nodiscard]] MaybeError
75 verify(boost::json::value const& value, std::string_view key) const
76 {
77 if (value.is_object() and value.as_object().contains(key)) {
78 using boost::json::value_to;
79 auto const res = value_to<T>(value.as_object().at(key));
80 if (value_ == res) {
81 return Error{Status{
82 RippledError::rpcNOT_SUPPORTED,
83 fmt::format("Not supported field '{}'s value '{}'", std::string{key}, res)
84 }};
85 }
86 }
87 return {};
88 }
89};
90
94template <>
95class NotSupported<> final {
96public:
105 [[nodiscard]] static MaybeError
106 verify(boost::json::value const& value, std::string_view key)
107 {
108 if (value.is_object() and value.as_object().contains(key)) {
109 return Error{Status{
110 RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\''
111 }};
112 }
113
114 return {};
115 }
116};
117
121template <typename... T>
122NotSupported(T&&... t) -> NotSupported<T...>;
123
127template <typename... Types>
128struct Type final {
139 [[nodiscard]] MaybeError
140 verify(boost::json::value& value, std::string_view key) const
141 {
142 if (not value.is_object() or not value.as_object().contains(key))
143 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
144
145 auto& res = value.as_object().at(key);
146 auto const convertible = (checkTypeAndClamp<Types>(res) || ...);
147
148 if (not convertible)
149 return Error{Status{RippledError::rpcINVALID_PARAMS}};
150
151 return {};
152 }
153};
154
158template <typename Type>
159class Between final {
160 Type min_;
161 Type max_;
162
163public:
170 explicit Between(Type min, Type max) : min_{min}, max_{max}
171 {
172 }
173
182 [[nodiscard]] MaybeError
183 verify(boost::json::value const& value, std::string_view key) const
184 {
185 using boost::json::value_to;
186
187 if (not value.is_object() or not value.as_object().contains(key))
188 return {}; // ignore. field does not exist, let 'required' fail instead
189
190 auto const res = value_to<Type>(value.as_object().at(key));
191
192 // TODO: may want a way to make this code more generic (e.g. use a free
193 // function that can be overridden for this comparison)
194 if (res < min_ || res > max_)
195 return Error{Status{RippledError::rpcINVALID_PARAMS}};
196
197 return {};
198 }
199};
200
204template <typename Type>
205class Min final {
206 Type min_;
207
208public:
214 explicit Min(Type min) : min_{min}
215 {
216 }
217
226 [[nodiscard]] MaybeError
227 verify(boost::json::value const& value, std::string_view key) const
228 {
229 using boost::json::value_to;
230
231 if (not value.is_object() or not value.as_object().contains(key))
232 return {}; // ignore. field does not exist, let 'required' fail instead
233
234 auto const res = value_to<Type>(value.as_object().at(key));
235
236 if (res < min_)
237 return Error{Status{RippledError::rpcINVALID_PARAMS}};
238
239 return {};
240 }
241};
242
246template <typename Type>
247class Max final {
248 Type max_;
249
250public:
256 explicit Max(Type max) : max_{max}
257 {
258 }
259
268 [[nodiscard]] MaybeError
269 verify(boost::json::value const& value, std::string_view key) const
270 {
271 using boost::json::value_to;
272
273 if (not value.is_object() or not value.as_object().contains(key))
274 return {}; // ignore. field does not exist, let 'required' fail instead
275
276 auto const res = value_to<Type>(value.as_object().at(key));
277
278 if (res > max_)
279 return Error{Status{RippledError::rpcINVALID_PARAMS}};
280
281 return {};
282 }
283};
284
289 std::string format_;
290
291public:
297 explicit TimeFormatValidator(std::string format) : format_{std::move(format)}
298 {
299 }
300
309 [[nodiscard]] MaybeError
310 verify(boost::json::value const& value, std::string_view key) const;
311};
312
316template <typename Type>
317class EqualTo final {
318 Type original_;
319
320public:
326 explicit EqualTo(Type original) : original_{std::move(original)}
327 {
328 }
329
338 [[nodiscard]] MaybeError
339 verify(boost::json::value const& value, std::string_view key) const
340 {
341 using boost::json::value_to;
342
343 if (not value.is_object() or not value.as_object().contains(key))
344 return {}; // ignore. field does not exist, let 'required' fail instead
345
346 auto const res = value_to<Type>(value.as_object().at(key));
347 if (res != original_)
348 return Error{Status{RippledError::rpcINVALID_PARAMS}};
349
350 return {};
351 }
352};
353
358EqualTo(char const*) -> EqualTo<std::string>;
359
363template <typename Type>
364class OneOf final {
365 std::vector<Type> options_;
366
367public:
373 explicit OneOf(std::initializer_list<Type> options) : options_{options}
374 {
375 }
376
382 template <typename InputIt>
383 explicit OneOf(InputIt begin, InputIt end) : options_{begin, end}
384 {
385 }
386
395 [[nodiscard]] MaybeError
396 verify(boost::json::value const& value, std::string_view key) const
397 {
398 using boost::json::value_to;
399
400 if (not value.is_object() or not value.as_object().contains(key))
401 return {}; // ignore. field does not exist, let 'required' fail instead
402
403 auto const res = value_to<Type>(value.as_object().at(key));
404 if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_)) {
405 return Error{
406 Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}
407 };
408 }
409
410 return {};
411 }
412};
413
418OneOf(std::initializer_list<char const*>) -> OneOf<std::string>;
419
423class CustomValidator final {
424 std::function<MaybeError(boost::json::value const&, std::string_view)> validator_;
425
426public:
433 template <typename Fn>
434 requires std::invocable<Fn, boost::json::value const&, std::string_view>
435 explicit CustomValidator(Fn&& fn) : validator_{std::forward<Fn>(fn)}
436 {
437 }
438
448 [[nodiscard]] MaybeError
449 verify(boost::json::value const& value, std::string_view key) const;
450};
451
458[[nodiscard]] bool
459checkIsU32Numeric(std::string_view sv);
460
461template <class HexType>
462 requires(
463 std::is_same_v<HexType, ripple::uint160> || std::is_same_v<HexType, ripple::uint192> ||
464 std::is_same_v<HexType, ripple::uint256>
465 )
467makeHexStringValidator(boost::json::value const& value, std::string_view key)
468{
469 if (!value.is_string())
470 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
471
472 HexType parsedInt;
473 if (!parsedInt.parseHex(value.as_string().c_str()))
474 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "Malformed"}};
475
476 return MaybeError{};
477}
478
597
601struct Hex256ItemType final {
611 [[nodiscard]] static MaybeError
612 verify(boost::json::value const& value, std::string_view key)
613 {
614 if (not value.is_object() or not value.as_object().contains(key))
615 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
616
617 auto const& res = value.as_object().at(key);
618
619 // loop through each item in the array and make sure it is uint256 hex string
620 for (auto const& elem : res.as_array()) {
621 ripple::uint256 num;
622 if (!elem.is_string() || !num.parseHex(elem.as_string())) {
623 return Error{
624 Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."}
625 };
626 }
627 }
628 return {};
629 }
630};
631
632} // namespace rpc::validation
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is within a certain range.
Definition Validators.hpp:183
Between(Type min, Type max)
Construct the validator storing min and max values.
Definition Validators.hpp:170
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:423
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid according to the custom validation function stored.
Definition Validators.cpp:64
CustomValidator(Fn &&fn)
Constructs a custom validator from any supported callable.
Definition Validators.hpp:435
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is equal to the stored original.
Definition Validators.hpp:339
EqualTo(Type original)
Construct the validator with stored original value.
Definition Validators.hpp:326
Max(Type max)
Construct the validator storing max value.
Definition Validators.hpp:256
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is not greater than max.
Definition Validators.hpp:269
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is not smaller than min.
Definition Validators.hpp:227
Min(Type min)
Construct the validator storing min value.
Definition Validators.hpp:214
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify whether the field is supported or not.
Definition Validators.hpp:75
NotSupported(T val)
Constructs a new NotSupported validator.
Definition Validators.hpp:63
static MaybeError verify(boost::json::value const &value, std::string_view key)
Verify whether the field is supported or not.
Definition Validators.hpp:106
A validator that forbids a field to be present.
Definition Validators.hpp:47
OneOf(std::initializer_list< Type > options)
Construct the validator with stored options of initializer list.
Definition Validators.hpp:373
OneOf(InputIt begin, InputIt end)
Construct the validator with stored options of other container.
Definition Validators.hpp:383
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is one of the stored options.
Definition Validators.hpp:396
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid formatted time.
Definition Validators.cpp:45
TimeFormatValidator(std::string format)
Construct the validator storing format value.
Definition Validators.hpp:297
std::expected< void, Status > MaybeError
Return type used for Validators that can return error but don't have specific value to return.
Definition Types.hpp:36
std::unexpected< Status > Error
The type that represents just the error part of MaybeError.
Definition Types.hpp:56
A status returned from any RPC handler.
Definition Errors.hpp:65
A group of custom validation functions.
Definition Validators.hpp:482
static CustomValidator uint160HexStringValidator
Provides a commonly used validator for uint160(AccountID) hex string.
Definition Validators.hpp:535
static CustomValidator credentialTypeValidator
Provides a validator for validating credential_type.
Definition Validators.hpp:595
static CustomValidator accountValidator
Provides a commonly used validator for accounts.
Definition Validators.hpp:504
static CustomValidator ledgerTypeValidator
Provides a validator for ledger type.
Definition Validators.hpp:497
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:557
static CustomValidator accountTypeValidator
Provides a validator for account type.
Definition Validators.hpp:527
static CustomValidator accountMarkerValidator
Provides a commonly used validator for markers.
Definition Validators.hpp:519
static CustomValidator issuerValidator
Provides a commonly used validator for issuer type.
Definition Validators.hpp:564
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:489
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:581
static CustomValidator subscribeAccountsValidator
Provides a validator for validating accounts used in subscribe/unsubscribe.
Definition Validators.hpp:574
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:588
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:543
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:551
static CustomValidator subscribeStreamValidator
Provides a validator for validating streams used in subscribe/unsubscribe.
Definition Validators.hpp:569
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:511
Validates that the elements of the array is of type Hex256 uint.
Definition Validators.hpp:601
static MaybeError verify(boost::json::value const &value, std::string_view key)
Validates given the prerequisite that the type of the json value is an array, verifies all values wit...
Definition Validators.hpp:612
A validator that simply requires a field to be present.
Definition Validators.hpp:28
static MaybeError verify(boost::json::value const &value, std::string_view key)
Verify that the JSON value is present and not null.
Definition Validators.cpp:33
Validates that the type of the value is one of the given types.
Definition Validators.hpp:128
MaybeError verify(boost::json::value &value, std::string_view key) const
Verify that the JSON value is (one) of specified type(s).
Definition Validators.hpp:140