Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Validators.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "rpc/Errors.hpp"
23#include "rpc/common/Types.hpp"
24#include "rpc/common/ValidationHelpers.hpp"
25
26#include <boost/json/array.hpp>
27#include <boost/json/object.hpp>
28#include <boost/json/value.hpp>
29#include <fmt/format.h>
30#include <xrpl/basics/base_uint.h>
31#include <xrpl/protocol/ErrorCodes.h>
32
33#include <concepts>
34#include <ctime>
35#include <functional>
36#include <initializer_list>
37#include <string>
38#include <string_view>
39#include <utility>
40#include <vector>
41
42namespace rpc::validation {
43
47struct Required final {
55 [[nodiscard]] static MaybeError
56 verify(boost::json::value const& value, std::string_view key);
57};
58
65template <typename... T>
67
72template <typename T>
73class NotSupported<T> final {
74 T value_;
75
76public:
82 NotSupported(T val) : value_(val)
83 {
84 }
85
93 [[nodiscard]] MaybeError
94 verify(boost::json::value const& value, std::string_view key) const
95 {
96 if (value.is_object() and value.as_object().contains(key)) {
97 using boost::json::value_to;
98 auto const res = value_to<T>(value.as_object().at(key));
99 if (value_ == res) {
100 return Error{Status{
101 RippledError::rpcNOT_SUPPORTED,
102 fmt::format("Not supported field '{}'s value '{}'", std::string{key}, res)
103 }};
104 }
105 }
106 return {};
107 }
108};
109
113template <>
114class NotSupported<> final {
115public:
124 [[nodiscard]] static MaybeError
125 verify(boost::json::value const& value, std::string_view key)
126 {
127 if (value.is_object() and value.as_object().contains(key))
128 return Error{Status{
129 RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\''
130 }};
131
132 return {};
133 }
134};
135
139template <typename... T>
140NotSupported(T&&... t) -> NotSupported<T...>;
141
145template <typename... Types>
146struct Type final {
157 [[nodiscard]] MaybeError
158 verify(boost::json::value& value, std::string_view key) const
159 {
160 if (not value.is_object() or not value.as_object().contains(key))
161 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
162
163 auto& res = value.as_object().at(key);
164 auto const convertible = (checkTypeAndClamp<Types>(res) || ...);
165
166 if (not convertible)
167 return Error{Status{RippledError::rpcINVALID_PARAMS}};
168
169 return {};
170 }
171};
172
176template <typename Type>
177class Between final {
178 Type min_;
179 Type max_;
180
181public:
188 explicit Between(Type min, Type max) : min_{min}, max_{max}
189 {
190 }
191
200 [[nodiscard]] MaybeError
201 verify(boost::json::value const& value, std::string_view key) const
202 {
203 using boost::json::value_to;
204
205 if (not value.is_object() or not value.as_object().contains(key))
206 return {}; // ignore. field does not exist, let 'required' fail instead
207
208 auto const res = value_to<Type>(value.as_object().at(key));
209
210 // TODO: may want a way to make this code more generic (e.g. use a free
211 // function that can be overridden for this comparison)
212 if (res < min_ || res > max_)
213 return Error{Status{RippledError::rpcINVALID_PARAMS}};
214
215 return {};
216 }
217};
218
222template <typename Type>
223class Min final {
224 Type min_;
225
226public:
232 explicit Min(Type min) : min_{min}
233 {
234 }
235
244 [[nodiscard]] MaybeError
245 verify(boost::json::value const& value, std::string_view key) const
246 {
247 using boost::json::value_to;
248
249 if (not value.is_object() or not value.as_object().contains(key))
250 return {}; // ignore. field does not exist, let 'required' fail instead
251
252 auto const res = value_to<Type>(value.as_object().at(key));
253
254 if (res < min_)
255 return Error{Status{RippledError::rpcINVALID_PARAMS}};
256
257 return {};
258 }
259};
260
264template <typename Type>
265class Max final {
266 Type max_;
267
268public:
274 explicit Max(Type max) : max_{max}
275 {
276 }
277
286 [[nodiscard]] MaybeError
287 verify(boost::json::value const& value, std::string_view key) const
288 {
289 using boost::json::value_to;
290
291 if (not value.is_object() or not value.as_object().contains(key))
292 return {}; // ignore. field does not exist, let 'required' fail instead
293
294 auto const res = value_to<Type>(value.as_object().at(key));
295
296 if (res > max_)
297 return Error{Status{RippledError::rpcINVALID_PARAMS}};
298
299 return {};
300 }
301};
302
307 std::string format_;
308
309public:
315 explicit TimeFormatValidator(std::string format) : format_{std::move(format)}
316 {
317 }
318
327 [[nodiscard]] MaybeError
328 verify(boost::json::value const& value, std::string_view key) const;
329};
330
334template <typename Type>
335class EqualTo final {
336 Type original_;
337
338public:
344 explicit EqualTo(Type original) : original_{std::move(original)}
345 {
346 }
347
356 [[nodiscard]] MaybeError
357 verify(boost::json::value const& value, std::string_view key) const
358 {
359 using boost::json::value_to;
360
361 if (not value.is_object() or not value.as_object().contains(key))
362 return {}; // ignore. field does not exist, let 'required' fail instead
363
364 auto const res = value_to<Type>(value.as_object().at(key));
365 if (res != original_)
366 return Error{Status{RippledError::rpcINVALID_PARAMS}};
367
368 return {};
369 }
370};
371
376EqualTo(char const*) -> EqualTo<std::string>;
377
381template <typename Type>
382class OneOf final {
383 std::vector<Type> options_;
384
385public:
391 explicit OneOf(std::initializer_list<Type> options) : options_{options}
392 {
393 }
394
400 template <typename InputIt>
401 explicit OneOf(InputIt begin, InputIt end) : options_{begin, end}
402 {
403 }
404
413 [[nodiscard]] MaybeError
414 verify(boost::json::value const& value, std::string_view key) const
415 {
416 using boost::json::value_to;
417
418 if (not value.is_object() or not value.as_object().contains(key))
419 return {}; // ignore. field does not exist, let 'required' fail instead
420
421 auto const res = value_to<Type>(value.as_object().at(key));
422 if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_))
423 return Error{
424 Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}
425 };
426
427 return {};
428 }
429};
430
435OneOf(std::initializer_list<char const*>) -> OneOf<std::string>;
436
440class CustomValidator final {
441 std::function<MaybeError(boost::json::value const&, std::string_view)> validator_;
442
443public:
450 template <typename Fn>
451 requires std::invocable<Fn, boost::json::value const&, std::string_view>
452 explicit CustomValidator(Fn&& fn) : validator_{std::forward<Fn>(fn)}
453 {
454 }
455
465 [[nodiscard]] MaybeError
466 verify(boost::json::value const& value, std::string_view key) const;
467};
468
475[[nodiscard]] bool
476checkIsU32Numeric(std::string_view sv);
477
478template <class HexType>
479 requires(
480 std::is_same_v<HexType, ripple::uint160> || std::is_same_v<HexType, ripple::uint192> ||
481 std::is_same_v<HexType, ripple::uint256>
482 )
484makeHexStringValidator(boost::json::value const& value, std::string_view key)
485{
486 if (!value.is_string())
487 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "NotString"}};
488
489 HexType parsedInt;
490 if (!parsedInt.parseHex(value.as_string().c_str()))
491 return Error{Status{RippledError::rpcINVALID_PARAMS, std::string(key) + "Malformed"}};
492
493 return MaybeError{};
494}
495
614
618struct Hex256ItemType final {
628 [[nodiscard]] static MaybeError
629 verify(boost::json::value const& value, std::string_view key)
630 {
631 if (not value.is_object() or not value.as_object().contains(key))
632 return {}; // ignore. If field is supposed to exist, let 'required' fail instead
633
634 auto const& res = value.as_object().at(key);
635
636 // loop through each item in the array and make sure it is uint256 hex string
637 for (auto const& elem : res.as_array()) {
638 ripple::uint256 num;
639 if (!elem.is_string() || !num.parseHex(elem.as_string())) {
640 return Error{
641 Status{RippledError::rpcINVALID_PARAMS, "Item is not a valid uint256 type."}
642 };
643 }
644 }
645 return {};
646 }
647};
648
649} // 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:201
Between(Type min, Type max)
Construct the validator storing min and max values.
Definition Validators.hpp:188
A meta-validator that allows to specify a custom validation function.
Definition Validators.hpp:440
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:82
CustomValidator(Fn &&fn)
Constructs a custom validator from any supported callable.
Definition Validators.hpp:452
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:357
EqualTo(Type original)
Construct the validator with stored original value.
Definition Validators.hpp:344
Max(Type max)
Construct the validator storing max value.
Definition Validators.hpp:274
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:287
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:245
Min(Type min)
Construct the validator storing min value.
Definition Validators.hpp:232
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify whether the field is supported or not.
Definition Validators.hpp:94
NotSupported(T val)
Constructs a new NotSupported validator.
Definition Validators.hpp:82
static MaybeError verify(boost::json::value const &value, std::string_view key)
Verify whether the field is supported or not.
Definition Validators.hpp:125
A validator that forbids a field to be present.
Definition Validators.hpp:66
OneOf(std::initializer_list< Type > options)
Construct the validator with stored options of initializer list.
Definition Validators.hpp:391
OneOf(InputIt begin, InputIt end)
Construct the validator with stored options of other container.
Definition Validators.hpp:401
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:414
MaybeError verify(boost::json::value const &value, std::string_view key) const
Verify that the JSON value is valid formatted time.
Definition Validators.cpp:63
TimeFormatValidator(std::string format)
Construct the validator storing format value.
Definition Validators.hpp:315
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:55
std::unexpected< Status > Error
The type that represents just the error part of MaybeError.
Definition Types.hpp:75
A status returned from any RPC handler.
Definition Errors.hpp:84
A group of custom validation functions.
Definition Validators.hpp:499
static CustomValidator uint160HexStringValidator
Provides a commonly used validator for uint160(AccountID) hex string.
Definition Validators.hpp:552
static CustomValidator credentialTypeValidator
Provides a validator for validating credential_type.
Definition Validators.hpp:612
static CustomValidator accountValidator
Provides a commonly used validator for accounts.
Definition Validators.hpp:521
static CustomValidator ledgerTypeValidator
Provides a validator for ledger type.
Definition Validators.hpp:514
static CustomValidator currencyValidator
Provides a commonly used validator for currency, including standard currency code and token code.
Definition Validators.hpp:574
static CustomValidator accountTypeValidator
Provides a validator for account type.
Definition Validators.hpp:544
static CustomValidator accountMarkerValidator
Provides a commonly used validator for markers.
Definition Validators.hpp:536
static CustomValidator issuerValidator
Provides a commonly used validator for issuer type.
Definition Validators.hpp:581
static CustomValidator ledgerIndexValidator
Provides a commonly used validator for ledger index.
Definition Validators.hpp:506
static CustomValidator currencyIssueValidator
Validates an asset (ripple::Issue).
Definition Validators.hpp:598
static CustomValidator subscribeAccountsValidator
Provides a validator for validating accounts used in subscribe/unsubscribe.
Definition Validators.hpp:591
static CustomValidator authorizeCredentialValidator
Provides a validator for validating authorized_credentials json array.
Definition Validators.hpp:605
static CustomValidator uint192HexStringValidator
Provides a commonly used validator for uint192 hex string.
Definition Validators.hpp:560
static CustomValidator uint256HexStringValidator
Provides a commonly used validator for uint256 hex string.
Definition Validators.hpp:568
static CustomValidator subscribeStreamValidator
Provides a validator for validating streams used in subscribe/unsubscribe.
Definition Validators.hpp:586
static CustomValidator accountBase58Validator
Provides a commonly used validator for accounts.
Definition Validators.hpp:528
Validates that the elements of the array is of type Hex256 uint.
Definition Validators.hpp:618
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:629
A validator that simply requires a field to be present.
Definition Validators.hpp:47
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:52
Validates that the type of the value is one of the given types.
Definition Validators.hpp:146
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:158